not ambiguous, just displeasing
(Integer | 1,)
(my-object | b | c)
(MyType | my-object | b | c,)
The | is used in a lot of places to delineate between 'the type' and 'the code' inside of list creation (type | ...elements...), methods and blocks [type | ...code...], new object {type | ...code list...}.
We have also been using | for creating a pipeline flow between objects especially when using Maybe.
This is too much |. As we can see from the examples above, even with syntax highlighting it is not easy to figure out what's going on. The second and third lines seem identical yet one makes a list and the other doesn't. That little , at the very end is the only thing between you and a compilation error or may be even a runtime mistake.
There's two things I'd like to do to fix this. The first is to stop overloading (subexpressions) and (lists, lists, lists). For that we need to use another piece of syntax for the language which was something I was trying to avoid doing. But let's go with something obvious - lists will now be denoted between angle brackets <1, 2, 3> which means we can have single element lists without the extra comma <1>.
With this comes a new syntactical burden. Consider this:
a < b then: [self do-something]
<b then: [self do-something]
<a, b> is-empty then: [self do-something]
The burdeon is this: <=> is a valid binary selector, so is foo> and else|. That means that <a> is also a "valid" binary selector. Yet it now needs to be a list. < a > is also a valid list but could be interpreted as a message send "less than a".
I'm not entirely sure that <a> isn't a completely valid binary selector too. But the sake of our sanity let's try and create a rule that makes sure this isn't a problem. OR, we have to swap out <> for «» (command+\ command+shift+\).
The first rule is for binary selectors. Binary selectors can start with alphanumerics but once they hit a symbol, eg: < | > they can only be symbols until the end of that selector. That means <a> is not a valid binary selector and must therefore be a list.
The second rule is that binary selectors must have a left-hand-side expression. You cannot use the anonymous receiver. This is okay: [age < 18] but this is not: [< 18].
As for parsing, that means that expression <
must be a binary-selector send, while < a
must be the start of a list and a close > is expected.
The next part of fixing the | problem is to stop using it for flow. Instead we'll borrow a page out of our own book which is else| – this follows the binary selector rule which means else| a else| b else| c is not a keyword selector, while else: a else: b else: c is. Let's instead use else> as our selector and get rid of | entirely.
Rewinding back to previous posts and other languages let's be explicit about what we want the flow to be or mean:
people where> [!is-done] copy> stdout do> [mark-done] else> panic
Now we gain the benefit of the Smalltalk like select:, reject:, do:, etc and a visual indicator of which direction the data flows, all without the awkward keyword clashing people reject: [:e | e isDone] copy: stdout
doesn't work because you end up with a keyword of reject:copy: instead of two distinct messages. You also cannot use the Smalltalk ; cascade as you want to send it to the previously created flow object. The above has to be written this way in ANSI Smalltalk:
[((people reject: [:e | e isDone]) copy: stdout) do: [:e | e markDone]] on: Error do: [ObjectMemory quit]
We've successfully avoided the nesting brackets problem of ANSI Smalltalk.
The only problem is we now have an ambiguous case... making classes:
RGBA32
<r: UnsignedInteger8
g: UnsignedInteger8
b: UnsignedInteger8
a: UnsignedInteger8 = 255>
I was thinking of revisiting making classes. May be we should do that. May be it's as simple as this:
class: 'RGBA32'
variables:
<r: UnsignedInteger8,
g: UnsignedInteger8,
b: UnsignedInteger8,
a: UnsignedInteger8 = 255>
(It just dawned on me that the comma-less multiline creation of maps is not valid since we added end-of-line dot. back in to the language)
enumeration: 'Cardinality'
values: <UnsignedInteger | north = 1, east, south, west>
union: 'Pet'
variants: <Dog, Cat>
untagged-union: 'Overlay'
variables: <as-dog: Dog, as-cat: Cat>
I'll pontificate on this new shed colour for a bit and see how it feels in a few days/weeks time before updating the Syntax document.