Since there are no parentheses in function application, Rebol winds up with the somewhat sketchy aspect that you can't tell when looking at a WORD! or PATH! if it's going to give you a value or run arbitrary code.
Tonight I've reached a point in the generic tuple + path change such that /foo, .foo, foo., and foo/ are all forms of PATH! and TUPLE! that fit efficiently into a single cell. But once things like
foo. existed I had to make them do something... so I went ahead with trying my suggestion:
>> foo: 10 == 10 >> foo. == 10 >> foo/ ** Error: Terminal slash in PATH! did not follow ACTION! >> append/ [1 2 3] 4 == [1 2 3 4] >> append. ** Error: Picking from action on left of dot in TUPLE!
That's pretty great. (Error messages need some thought). And I noticed something else neat about terminal slash...which is that it makes a good shortcut for REEVAL to get a function value then force its execution:
>> (specialize 'add [value2: 10]) 20 == 20 ; GROUP! evaluated to an ACTION! and was discarded >> reeval (specialize 'add [value2: 10]) 20 == 30 ; this is how you previously did it without a new variable for the action >> (specialize 'add [value2: 10])/ 20 == 30 ; shorthand!
But Is There More Untapped Power Lurking Here?
My first thought went to protecting from Rebol's dangerous "always execute IF a function" semantics.
But being able to make member access look the same when calling a function or not is a sought-after ability in other languages. Most discussions of the feature involve "Property Getters and Setters"...where you can override non-parentheses access and assignment for a field. For instance, in C#:
"Properties combine aspects of both fields and methods. To the user of an object, a property appears to be a field, accessing the property requires the same syntax. To the implementer of a class, a property is one or two code blocks, representing a get accessor and/or a set accessor"
By its nature, Rebol has "getters" because you don't need parentheses to get an object member. Just make a function with no arguments:
>> my-object: make object! [ x-private: 10 x: func  [ print "Getting X!" return x-private + 20 ] ] >> my-object/x Getting X! == 30
But it doesn't have overrideable behavior for SET-PATH! or SET-WORD!, so you can't make something like
my-object/x: 10 call code. The X function just gets overridden.
The little inkling of a thought I had was that we might be able to use the PATH!/TUPLE! distinction somehow to tell the difference between calling the setter/getter function and dealing with the function itself.
>> foo/x: 1000 Calling the Setter Function! == 1000 ; imagine setter stores value - 20 >> foo/x-private == 980 ; ...so it updated the private value >> foo/x Getting X == 1000 >> foo/x.: <dead> ; notice the `.` == <dead> >> foo/x == <dead> ; no setter or getter anymore
Where my train of thought was going with this is that all the historical uses of
/ would be willing to call getters and setters (if they existed).
It's just an inkling at this point of something that might be interesting. I was kind of lamenting how many
/ there are in the codebase, when it seemed to me I'd be wanting to use
. almost always. But that got me to wondering about the kinds of motivations that people would have for using one form vs. the other. Maybe this plays into it.
All that aside... really just kind of announcing that generic tuple and path unification with compression to single cells is coming up shortly. There are a few "big" issues to think about, but the mechanics are working...for the most part.