admin@gw] > /import myscript.rsc
myscript start
not debugging
myscript end
Script file loaded and executed successfully
[admin@gw] > :global debugmyscript true
[admin@gw] > /import myscript.rsc
myscript start
debugging
conditional is not boolean
[admin@gw] >
In a more complex script it would be harder to find out which line gives the “conditional is not boolean” error, and the condition does not have to be boolean because very often is converted to boolean:
The basic logic is 0 is “false”, and all other numbers make a bool “true”. Provide any other type in a [:tobool] the bool becomes will get you a [:nothing] type (“nil”). e.g.
IMO it the “nil” that makes the [:typeof]=“bool” less than useful - sometimes [:nothing] is not same as false.
But since the config uses “yes” and “no” and does NOT take a bool type instead.
IMO you’re better off use the string “yes” or “no” instead of bool — since those can be use in scripts and some :if ($myvar = “yes”) is just as clear. The side-effects of the “nil” add unnecessary complexity in in already complex scripting language.
So do that, or more logically stop using string as true/false values, no mater if the string have the characters “true” or “false” inside and also as yes/no for true / false
then leave other considerations aside, such as -1 = True, 0 = False on some cases…
(with only 1 bit, the last bit for “negative” is the only bit available, so the numbers on that bit value can be only 0 and -1, so set = true (-1) and unset = 0 (false) )
RouterOS inconsistency (synthesis: use true/false on script processing, yes/no on config commands)
In my opinion the inconsistency is the problem: if the operator !$a works, :if ($a) should also work and vice versa.
Of course, in scripts one avoids using strings as :if statement condition, but sometimes is quite unexpected that a boolean turns into string, for example:
In this case the argument is converted to string unless put into ().
In other cases strings are converted into non strings. One might expect that “$a” is a string, but no, it is $a.
Ome other examples of unexpected type conversions:
These examples show exactly what the result SHOULD look like, so what’s wrong with these examples results, is your expectations.
Just write the scripts properly.
This is just a forcing.
When happening this on one script, if is just made for this case?
:put [:typeof "$(true)"]
[admin@Mikrotik] > :put [:typeof "yes"]
str
# correct!!! yes is just one string
[admin@Mikrotik] > :put [:typeof "true"]
str
# correct!!! yes is just one string
[admin@Mikrotik] > :put [:typeof "$(true)"]
bool
# correct!!! "$(true)" is translated into $(true) since is just one $ element, and ( ) provide the result of internal
# operation that is boolean true (not "true"), so $(true) is obviously true and :typeof of true, is obvious that is boolean
[admin@Mikrotik] > :put [:typeof "$(yes)"]
bool
# same as before
[admin@Mikrotik] > :global a 0
[admin@Mikrotik] > :put [:typeof "$a"]
num
[admin@Mikrotik] > :put [:typeof "$($a)"]
num
# same as before "$($a)" is translated to $($a), then $() mean put here the result of $a, so $a is a num, and the result is a num....
Correct example
:global a 1
:global b 2
[admin@Mikrotik] > :put [:typeof "$($a + $b)"]
num
[admin@Mikrotik] > :put "$($a + $b)"
3
Mikrotik+us are in a bit a box... the #1 rules is existing script have to still work - so some inconsistencies" cannot be fixed, since folk may rely on the "wrong" behavior. And also there just are a lot implicit type conversations - since script and config are same system. So as "config language", scripting engine has to be forgiving on someone using ="1" vs =1 in a set. This logic gets you into the current state.
Basically you're better off using :more [:typeof $x] perhaps with [:tonum]/whatever if doing any if/logic with something if you want to be "safe". i.e. convert and check types yourself if it matters in logic...
But boolean logic like ! on something your not SURE of it's type is bad idea. Since you're not wrong – boolean are inconsistent. So the resulting operators are also too! Best just not to do stuff like !$x unless your script created the $x using no-quotes true or false. Stuff like !($x = 1) is okay, since the result of an = expression is a bool type.
At the end of the day, scripts variables get marshaled to/from strings, so type information is always inferred, not "saved". This is especially "true" or true for booleans, since it "upconverts" strings to the booleans IF NEEDED in expression. But the bool variables are fake! Similar things with ip address types, as router, the type inference prefers ip in some cases. (i.e. :global mynum 1.1 - will get you an ip address of 1.0.0.1 since original RFC said that was okay for an ip address). Why [:typeof] is best defense you have.
In terms of scripting docs... it's true do not give a lot of guidance how "how to" or have deeper reference on things like types and script lifecycle. There is a "tip and ticks" section that is helpful – it shows the "worst" gotchas. And @rextended's pinned "snippets" post have more good examples.
And this is real crime here. You should be able to pass a bool to a "/interface/ethernet set enabled=$mybool" but @rextended is right - commands need the "yes" or "no" string. Worse scripting has no casting to convert bool to "yes"/"no" format.