Devlog: UCL — Assignment
Toying with changing how assignment works in UCL. Up to now, assigning a variable to a value involved calling the set
command, which took a variable name, and the value to assign:
set a "hello"
$a
--> "hello"
This has been fine, but I’m now running into few limitations with this approach. The first is that it doesn’t support setting subscript values within lists or values. Because set
is just a regular command, the parser will evaluate any dot or sub-pipe expressions prior to invoking set
. One way around this is to quoted the variable to assign as a string:
set list [1 2 3]
set "$list.(1)" 4
But this looks ugly, and will involve another pass of the parser every time set
is called.
Another approach is converting set
to a macro, which receives the arguments as the parse tree. This gives set
more control over how to interpret the arguments. But it doesn’t resolve the second issue, which is an inconsistency introduced with a new feature I’m planning.
I want to add the notion of pseudo variables, which act like regular variables except that getting or setting them will invoke some hander logic from the embedding system, rather than set a value in memory. Think of them similar to how document
and window
work in a browser’s JavaScript runtime. My plan for them is to embed this Dynamo Browse to allow the user to access or modify the result-set or selected item, which will result in the UI changing. I’m sure I’ll have more to say about that in the future.
To distinguish them from normal variables, they’ll have an at-sign instead of a dollar sign:
@value
--> something
But as far as the user is concerned, they should act just like normal variables. And just like normal variables, they should be modifiable using the set
command. I don’t want the variable and pseudo-variable to share the same namespace (since they look different, there’s no reason for them to share one), so I needed a way to distinguish between setting a pseudo-variable from a regular variable.
This first means they needed to be quoted but I hacked a quick version of set
on this feature branch to
support setting them:
set "@value" "new value"
But compare this with the first example. Notice that when we were setting a
, we didn’t need to include the dollar sign. Here we have a case where one sort of variable requires the prefix symbol, and the other doesn’t. This form of inconsistency was not appealing to me.
Since the various modes of assignments has outgrown the ability of one command to do it all, I’ve decided to remove set
and add basic assignments to the language. These look like typical assignments you see in most other languages:
$a = "hello"
$a
--> "hello"
But they’ll be able to fix the issues from using set
, such as assign the value of subsets and showing consistent representation of what you’re actually trying to modify:
@value = "new value"
$list = [1 2 3]
$list.(1) = 4
$list
--> [1 4 3]
It also leads to some improvements of the common case. One small issue with using set
is that it always required one to wrap the result of a sub-expression in parenthesis.
set h (strs:to-upper "Hello")
But since this is a grammar change, these parenthesis are no longer necessary.
$h = strs:to-upper "Hello"
$h = "Hello" | strs:to-upper
There may also be room for different forms of assignment, such as ensuring the value you’re trying to set is not nil. There was a variant of set, called set!
, which threw an error when attempting to assign a variable to nil. This could be expressed as a different assignment form:
$h = "this is fine"
$h =! ()
--> error: trying to set $h to a nil value
I will acknowledge that doing this will mean loosing out on some theoretical benefits that came from using set
. For one thing, it will no longer be possible to indirectly set a value. You can’t, for example, do this:
set b "a"
set $b "hello"
$a
--> "hello"
I’ve never really needed to do this, but I could see this being potentially useful. One way to support this might be to do something similar to what Lua does, and expose the environment as a hash. Pseudo-variables could be useful here:
$b = "a"
@_G.($b) = "hello"
$a
--> "hello"
I’ll hold off from adding something like this until I absolutely need to.
So that’s the current idea. I spent around an hour on this so far, just trying it out and seeing how it feels, and I think it’s got promise. I’ll keep it on the feature branch for now, but I suspect this will eventually become the new way to do assignment in UCL going forward.