What does op type (>[ ... ]) do?

I was using this construction as kind of nested function. For example:

:local prefix
:local suffix
:local split (>[ 
	:local sat [:find key=":" in=$1]; 
	:set prefix [:pick $1 0 $sat]; 
	:set suffix [:pick $1 ($sat+1) 1000]
 ])

This one makes easier to split a string at the first : in case it is needed multiple times. Not the only solution but it works. But it also does something unexpected:

:local prefix
:local suffix
:local split (>[ 
	:local sat [:find key=":" in=$1]; 
	:set prefix [:pick $1 0 $sat]; 
	:set suffix [:pick $1 ($sat+1) 1000]
 ])

{
	:local abc 10;
	:put ("abc: $abc")
	$split "ghi:jkl"
	:put ("abc: $abc")
	:put ("prefix: $prefix")
	:put ("suffix: $suffix")
}

If you put this code into a script file and run with /import the output will be:

abc: 10
abc: 3
prefix: ghi
suffix: jkl
Script file loaded and executed successfully

Why did the variable abc got the value of 3?

I know, it is undocumented, but please, if you can say more about this, do it.

(ros v 7.16.2)

There is a detailed explanation written by others on the forum.

Aside from that when you notice a problem, it should be minimized to remove as many parameters as possible:
{
:local y ; # used later
:local z 10
:local j 11
:local x (>[:set y 44 ; :local deletek ; :local overwritew 19])
:local k 12
:local w 13
:put “y: $y”
:put “z: $z”
:put “j: $j”
:put “k: $k”
:put “w: $w”
$x
:put “y: $y”
:put “z: $z”
:put “j: $j”
:put “k: $k”
:put “w: $w”
}

y:
z: 10
j: 11
k: 12
w: 13
y: 44
z: 10
j: 11
k:
w: 19
The call of the function overwrite the value of the next declared variable because > is used.
Is one undocumented feature because is not done and not completely working.
Declaring first (as must be done) the variable, solve the “problem”…


Writing correctly often avoids unexpected situations…
{
:local sat
:local prefix
:local suffix
:local split (>[
:set sat [:find key=“:” in=$1]
:set prefix [:pick $1 0 $sat]
:set suffix [:pick $1 ($sat + 1) [:len $1]]
])

:local abc 10
:put “abc: $abc”
$split “ghi:jkl”
:put “abc: $abc”
:put “prefix: $prefix”
:put “suffix: $suffix”
}

abc: 10
abc: 10
prefix: ghi
suffix: jkl

The 10,000 foot[/meter] view of the (>) and its cousin (>{}) is that they are essentially a syntax-checked version of the [:parse] / :parse, since both interact with the "code" datatype.

:put (>[])     
(evl /)

But on the specifics here.... I'm not sure the (>[]) does anything special for a $split. There are MANY way to split a string... so complex, undocumented (>[]) syntax would NOT be the best approach.

Further, referencing local variables from inside on the "op" type is just asking for trouble, i.e. referencing out-of-scope locals is not allowed elsewhere, so arguable if even @rextended's code is just using what "bug". Philosophically functions should not have side-effects like touching out-of-scope variables. Now I guess view the (>) as the "functional programming" operators, so anyone who knows LISP or Haskell that sees this would be aghast.

That being said if you really wanted to try use these new operators in a $split ... you're current code does not deal with splitting a string MULTIPLE times, which a typical $split function might do. While I don't know exactly off top-of-my-head, you MIGHT be able to construct some version use the "activate-in-context" ( ... < %% {} ) with [:convert to=byte-array] to access string as array — but I'm not sure that code be very readable or even shorter.



Main thread: A few undocumented operators that are kind of neat. A few undocumented operators that are kind of neat.

Also u discussed[/u] in: Persistent Environment Variables Persistent Environment Variables

u used as "inline function"[/u]: $INQUIRE - prompt user for input using arrays +$CHOICES +$QKEYS $INQUIRE - prompt user for input using arrays +$CHOICES +$QKEYS

The related( ... < %% {}) used in few places here: :face_with_monocle: example of automating VLAN creation/removal/inspecting using $mkvlan & friends... 🧐 example of automating VLAN creation/removal/inspecting using $mkvlan & friends...


IMO (>) best "use case" is to enable functions in array declaration as inline functions.

:local newarray {"var1"="data";"var2"=2;"fn1"=(>[:return something])}

vs.

:local newarray [:toarray ""]
:set ($newarray->"var1") "data"  
:set ($newarray->"var2") 2  
:set ($newarray->"fn1") do={:return "something"}

And don't forget there the is (>{}) syntax too, which adds another twist:

:put (>{1+1})        
(+ 1 1)

:put [(>{1+1})]
2

All this gets complex since the underlying "evl" / code type is not documented. Now the (>) etc allow another method to inject code into the final "evl"/code type that is what's executed, but predicting exactly what might happen take more time - and risky if you violating basic scripting rules like local vars setting out-of-scope local vars that could change in next releases.

Thank you.

I used this construct in script file to abbreviate a series of commands, expressions.
As I wrote, kind of embedded function, that can access local variables. It makes code shorter and more readable.

Thank you, for pointing out the state of this feature, I’ll avoid using it in unsupervised conditions like event scripts.

I guess I never thought about this, but it does make some sense…

The "locals in the calling scope " are available the script in the (>[…]). Since the outer (>…) returns a function, and the in the inner that returns a code data-type. So using the (>) function essentially becomes “inlined” (NOT pushed to the call stack), thus the local variables are in scope. While the do={} does create a new scope (and function pushed to call stack), so locals in a parent scope are NOT available.

Perhaps the more simple example:

# version 1
{
    :local x 1
    :local fn do={:put $x}
    $fn
}
# prints nothing, since $x is not in scope

# version 2
# vs, using (>[]) which creates a function that returns a code data-type, and prints "2"
{
    :local x2 2
    :local fn2 (>[:put $x2])
    $fn2
}
2

And you can see the RouterOS’s “IL”, between the two versions — one uses a “/localdo=” while another treat the (>) as just another local (“/localname=”)

# version 1
(evl / (evl /localname=$x;value=1) (evl /localdo=;(evl (evl /putmessage=$x));name=$fn) (<%% $fn (> $fn)))
# version 2
(evl / (evl /localname=$x2;value=2) (evl /localname=$fn2;value=(> (evl (evl /putmessage=$x2)))) (<%% $fn2 (> $fn2)))