<div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small">Hi Christoph,<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Nov 25, 2022 at 7:47 AM <<a href="mailto:christoph.thiede@student.hpi.uni-potsdam.de">christoph.thiede@student.hpi.uni-potsdam.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Hi Eliot,<br>
<br>
thanks for the great discussion. Your reply cleared a lot of things up for me -- I very much agree that the default value of any variable is not "undefined", but specifically nil.<br>
<br>
What I still find an interesting trade-off is that of "implicit vs explicit" aka "terseness vs readability". I think its solution depends on the typical readers of the code I am writing. If they are Squeak Core developers or VM developers, I can assume that they know the default value for any variable. For unexperienced programmers, I hope they do know. Still, it's easier for anyone to forget if it's not explicitly written down. Yes, I can translate <font color="#808080">|</font><font color="#000000"> </font><font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#808080">|</font> to <font color="#808080">|</font><font color="#000000"> </font><font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#008080"><i>:= nil</i></font><font color="#000000"> </font><font color="#808080">|</font> in my head, but that also might be a tiny portion of mental overhead.<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">Right.  One of the design principles of Smalltalk, one of its more important design principles, is to use the least amount of rules possible (but no fewer) and apply them consistently.  This applies, for example, to Maxwell's equations, right?  It is a critical attribute of good scientific models, good legal systems, good road traffic laws, not just good programming languages.  Finding a small set of easily memorable rules, or principles, that are orthogonal and cohere to provide a calculus which can be used to construct or predict behaviour or consequence, is a delight and a blessing.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">There was one rule in Smalltalk that was awful; that was a result of the implementation showing through, (that IIRC got into the ANSI standard), that we fixed. That was that the value of an empty block that took arguments, was the value of the last argument.  So [:a<span class="gmail_default"> :b</span>|] value: 1 value: 2 would evaluate to 2.  Thankfully this has been fixed and the value of an empty block is always nil, irrespective of its arguments. ColorArray new: n is not something that needs to be fixed, or alarmed at.  It can be experienced (I discovered it this last week, I was not astonished).  I wager you will never forget that the default value of a ColorArray indexed instance variable is Color transparent.  You may even use it in your teaching as an amusing and interesting example for the initialization rule. I doubt that it would tax any new Smalltalker that has already encountered bits collections, and would serve to help them remember the initialize-with-zero sub-rule.</div><div class="gmail_default" style="font-size:small"><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Example 2, ColorArray: My first take would be indeed be to favor <font color="#000000">ColorArray</font><font color="#000000"> </font><font color="#000080">new:</font><font color="#000000"> </font><font color="#800000">256</font><font color="#000000"> </font><font color="#000080">withAll:</font><font color="#000000"> </font><font color="#000000">Color</font><font color="#000000"> </font><font color="#000080">transparent</font> over <font color="#000000">ColorArray</font><font color="#000000"> </font><font color="#000080">new:</font><font color="#000000"> </font><font color="#800000">256</font>, because I have never used this class before and would not be sure whether the values default to black or transparent or anything else. I could look it up, but I would likely forget it several times before remembering. Why should I do this to myself (and to any other non-ColorArray expert)?<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">The thing about ColorArray that's important to our discussion is that a new instance is initialized; it doesn't contain random crap. This is the point about initialization that applies to all Smalltalk variables, temporary, global, named instance, and indexed instance.  We have one rule, if the variable holds pointers it is initialized by nil, if the variable holds bits it is initialized with the all-zeros bit string.  This has some unexpected consequences such as (ColorArray new: 10) anyOne = Color transparent, but the nice thing is that the rule is very easy to learn, and so when one discovers (ColorArray new: 10) anyOne = Color transparent one is not astonished. [the principle of least astonishment)</div><div class="gmail_default" style="font-size:small"><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<br>
Example 3, point arithmetic: Here I'm completely with you, but maybe I'm also biased because I have already spent some time working with visual domains in Squeak. :-)<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">:-) indeed!</div><div class="gmail_default" style="font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Example 4, coreutils: ls, cat, and less are all lisping, catastrophic, or at least less intuitive names IMHO. Most of us will have got familiar with them, but from a Smalltalk perspective that is seeking for readability, I still would favor them to be named ListFiles, PrintFile, and OpenFileForRead. On the contrary, many people who are used the present nomenclature would dismiss these proposals as hard to write and maybe even hard to read. Is "terseness vs readability" as this syntactical point really a matter of data (code) quality (that must be ensured by the writer), or more a matter of the right tooling (that can be adjusted by the editor/reader)?<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">Learning to play a musical instrument, learning to wield a golf club, learning to drive a car, ride a bike, accumulate any useful skill, involves a tradeoff.  Masterful use always drops the training wheels. Eventually we always advance to using a functionally efficient interface and/or set of skills.  This makes like hard for the learner.  They have to acquire the skills that allow them to reach competence on their way to mastery.  But we do not serve ourselves by preventing mastery, by protecting us against mastery.  If we do, we end up with inexpressive music, shirt and unexciting drives, 30 kph autobahns, 70 kg bikes that don;'t lean in the corners.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">The Prussian Model of Education was set up under Bismark, its intent being to produce a generation of easily ruled consumers and cannon fodder. Its means were to teach badly, to render its subjects insecure, consciously inferior to those educated in elite private schools. This model was adopted by th eUS senate immediately after the civil war as the blueprint for the US's public education system. It serves as the ideal instrument of oppression in faux democracies. [I was incredibly fortunate that it was not used in my public primary school; unsurprisingly, teachers that love children hate the Prussian Model].</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">Driving a child to school, rather than having them walk, and/or catch a bus, results in an adult less at ease moving around the city.  It infantilises them. It constrains them their whole lives.</div><div class="gmail_default" style="font-size:small"><div class="gmail_default"><br></div><div class="gmail_default">Wittgenstein's realisation was that language means what we collectively decide it means, not what it is defined to mean, and the fact that a substantial number of American adults think that "inflammable" means the opposite of "flammable" is alarming, an example that militates for better teaching, not Newspeak.</div></div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">If we are to live meaningful, rich, lives that enrich those of others, we must enculturate, we must take off the training wheels, we must fashion that which is concise, powerful and call it elegant.</div><div class="gmail_default" style="font-size:small"><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">---<br>
<br>
> I want a warning for the usage of b in "c := b", "d" in "#(1 2 3) sorted: d", g in "g perform: #ifNotNil: with: [b := g]".  I *don't* want to be told about a in "a ifNil: [a := 1]", c in "c ifNil: [c := 3]", or e & f in "(e isNil or: [f isNil]) ifTrue: [e := f := 6]".<br>
<br>
Thank you for clarification. So the idea of #queryUndefined (will rename that) is to fix human forgetfulness.</blockquote><div><br></div><div class="gmail_default" style="font-size:small">Yes.</div><div class="gmail_default" style="font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"> In the second group of examples, you explicitly consider these variables being nil, so you don't need a reminder from the compiler (or with regards to Tobi's argument, you're already dealing with the meta-level). In the first group of examples, one could say that you are covering tracks of your own possible forgetfulness and spreading possibly unsassigned values, so it's more important for the tooling to point you to that possible slip. Yes, I guess now that makes more sense to me. :-)<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">Cool.</div><div class="gmail_default" style="font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<br>
Still, the scope of this warning remains a bit blurry for me. Maybe that's because we are approximating a type analysis engine here with a *very* rough heuristic. </blockquote><div><br></div><div class="gmail_default" style="font-size:small">I think that's exactly why.</div><div class="gmail_default" style="font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">For instance:<br>
<br>
    <font color="#808080">|</font><font color="#000000"> </font><font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#808080">|</font><font color="#000000"><br>
</font>    <font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#000080">ifNotNil:</font><font color="#000000"> </font><font color="#000000">[</font><font color="#6B6B6B">a</font><font color="#000000"> </font><b>:=</b><font color="#000000"> </font><font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#000080">+</font><font color="#000000"> </font><font color="#800000">1</font><font color="#000000">]</font><font color="#000000">.</font><font color="#000000"><br>
</font>    <font color="#800000">^ </font><font color="#6B6B6B">a</font><br>
<br>
In this example, I do *not* want a warning for "<font color="#6B6B6B">a</font><font color="#000000"> </font><font color="#000080">+</font><font color="#000000"> </font><font color="#800000">1</font>" but I *do* want a warning for "<font color="#800000">^ </font><font color="#6B6B6B">a</font>" as a still might be unassigned. Currently, the reality is just the other way around. But that is probably out of scope for the current architecture ...<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">I love the pragmatic design principle from the LRG/SCG at PARC that I was taught on arrival at ParcPlace Systems: don't let the perfect be the enemy of the good.  It's ok to have 95% of the solution.</div><div class="gmail_default" style="font-size:small"><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">(As a side note, some other confusing thing around this notification for me is the fact that our compiler essentially integrates a few rudimentary linter tools (namely, UndefinedVariable and UnknownSelector) and forces the user to interact with them in a modal fashion. To be honest, I never liked that "modal linter style" and often wish we had some more contemporary annotation-/wiggle-line-based tooling for that. </blockquote><div><br></div><div class="gmail_default" style="font-size:small">+1000 !!!!!  Thanks for pointing this out.  This is an excellent suggestion.  I *hate* clicking on the "declare as a foo variable" dialog for a sequence of as-yet-undeclared temp vars, only to hit a lint rule, or syntax error, and have all those declarations discarded.</div><div class="gmail_default" style="font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">My typical interaction with #queryUndefined looks like this: me: accept new code, compiler: you did not assign foobar, me: oops, you're right, let me fix that; or alternatively: yes, that was intended, let me explicate that. Ignoring and proceeding from this warning has never felt acceptable for me as this would put the same confusion on any future editor of the method.)<br>
<br>
> :-)  Hope I'm not too strident :-)<br>
<br>
No problem, it was very interesting and I learn a lot from your replies. :-)<br>
<br>
Best,<br>
Christoph<br>
<br>
<font color="#808080">---<br>
</font><font color="#808080"><i>Sent from </i></font><font color="#808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk" target="_blank"><u><font color="#808080">Squeak Inbox Talk</font></u></a></i></font><br>
<br>
On 2022-11-22T23:36:09-08:00, <a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a> wrote:<br>
<br>
> Hi Christoph, Hi Marcel,<br>
> <br>
> apologies about the font size mismatches...<br>
> <br>
> On Wed, Nov 23, 2022 at 2:25 AM Marcel Taeumel <marcel.taeumel at <a href="http://hpi.de" target="_blank">hpi.de</a>><br>
> wrote:<br>
> <br>
> > Hi Christoph --<br>
> ><br>
> > >  IMHO, it unnecessarily complicates the simple Smalltalk syntax.  [...]<br>
> ><br>
> > Nah, this is just a tooling change, not a syntactical one.<br>
> ><br>
> <br>
> +1<br>
> <br>
> ><br>
> > Yes, I would like to have this info skipped for #isNil as well. Note that one<br>
> > should not use  #ifNotNilDo: anymore.<br>
> ><br>
> <br>
> Good idea.  I'll include it.<br>
> <br>
> ><br>
> > Best,<br>
> > Marcel<br>
> ><br>
> > Am 23.11.2022 11:00:43 schrieb Thiede, Christoph <<br>
> > christoph.thiede at <a href="http://student.hpi.uni-potsdam.de" target="_blank">student.hpi.uni-potsdam.de</a>>:<br>
> ><br>
> > Hi Eliot, hi all,<br>
> ><br>
> ><br>
> > I'm skeptical about this change, as it creates or expands a special role<br>
> > of the selectors #ifNil:, #ifNotNil:, and their combinations. IMHO, it<br>
> > unnecessarily complicates the simple Smalltalk syntax. While I know and<br>
> > sometimes dislike these UndefinedVariable notifications, too, I don't know<br>
> > whether differentiating them by the selector is the right strategy<br>
> > to improve this situation.<br>
> ><br>
> > Please indulge me.  It's f***ing irritating to be told by the compiler<br>
> that as temp var appears to be uninitialized when one is intentionally<br>
> using the fact that temps are initialized to nil.  And that temp vars are<br>
> initialized to nil is a) essential knowledge and b) a good thing (no<br>
> uninitialized local variables a la C, a sensible value to initialize a<br>
> variable with).<br>
> <br>
> BTW, I find it more than sad (a little alarming in fact) that<br>
> someSmalltalkers don't know that the value of several conditionals that<br>
> take blocks is nil when the condition doesn't select the block. e.g. false<br>
> ifTrue: [self anything] is nil.  I see "expr ifNotNil: [...] ifNil: [nil]"<br>
> and it strikes me as illiterate.  I recently visited code written by a<br>
> strong programmer who open coded a lot of point arithmetic, decomposing<br>
> e.g. a * b into (a x * b x) @ (a y * b y). It's bad.  It gradually<br>
> degrades the code base in that it isn't always an exemplar of best<br>
> practice,<br>
> <br>
> ><br>
> > Consider the following examples:<br>
> ><br>
> ><br>
> > | a b c d e f g h |<br>
> > a ifNil: [a := 1].<br>
> > c := b.<br>
> > c ifNil: [c := 3].<br>
> > #(1 2 3) sorted: d.<br>
> > e := 5.<br>
> > (e isNil or: [f isNil]) ifTrue: [e := f := 6].<br>
> > g perform: #ifNotNil: with: [b := g].<br>
> > h ifNotNilDo: [h := 8].<br>
> ><br>
> > How would you explain to a naive Smalltalker which of these variables will<br>
> > be marked as undefined at this point and why? (Of course, you can explain<br>
> > it by pointing to the implementation, but I think that's a significantly<br>
> > less intuitive explanation than just saying "you must declare any variable<br>
> > before using it".)<br>
> ><br>
> ><br>
> No. It's a hard-and-fast rule that all temp vars are initialized to nil.<br>
> And initializing a variable (to other than nil) is done by assigning it.<br>
> In the above a through h are declared within the vertical bars.n They are<br>
> initialized in the assignments.  I want a warning for the usage of b in "c<br>
> := b", "d" in "#(1 2 3) sorted: d", g in "g perform: #ifNotNil: with: [b :=<br>
> g]".  I *don't* want to be told about a in "a ifNil: [a := 1]", c in "c<br>
> ifNil: [c := 3]", or e & f in "(e isNil or: [f isNil]) ifTrue: [e := f :=<br>
> 6]".  I never want to see "ifNotNilDo", ever ;-)<br>
> (* note that a couple of years back we fixed a bad bug in the compiler<br>
> where block local temps were  not (re)initialized to nil on each iteration,<br>
> leaking their values from previous iterations, breaking the "all temp vars<br>
> are initialized to nil rule, and revealing implementation details in the<br>
> compiler's inlining of to:[by:]do: forms)<br>
> <br>
> > This behavior leads to a mental model that disambiguates between null and<br>
> > undefined similar to JavaScript which I never have found helpful.<br>
> ><br>
> ><br>
> I don't see how that applies.  Smalltalk has no undefined.  It has nil &<br>
> zero, and these values are used to initialize any and all variables.  This<br>
> is not an artifact of the implementation.  It is a fundamental part of the<br>
> language design.  It results in no dangling referents or<br>
> uninitialized variables.  The language used in Parser>>#queryUndefined is<br>
> problematic. It should be "unassigned", not "undefined". There is nothing<br>
> undefined about these variables.  But they are indeed unassigned.  In some<br>
> cases (see my i=diomatic implementation of subsequences: and substrings)<br>
> this can (and *should*) be used to advantage.  And all Smalltalk<br>
> programming courses should explain that variables are always initialized<br>
> (either to nil or zero, & hence by extension 0.0, Character null, Color<br>
> transparent, et al), and may need assignment before their referents get<br>
> sent messages.<br>
> <br>
> I see the same kind of sloppiness in people not knowing that conditionals<br>
> that take blocks typically evaluate to nil when the condition doesn;t<br>
> select the block.  So always "expr ifNotNil: [...]", never "expr ifNotNil:<br>
> [...] ifNil: [nil]", or "expr ifNotNil: [...] ifNil: []". I recently<br>
> cleaned up code by as string programmer who had open coded point arithmetic<br>
> (e.g. a * b written as (a x * b x) @ (a y * b y) ).  This is really bad:<br>
> it's exemplifying poor practice, it's verbose, it takes away at least as<br>
> much understanding as it conveys, it leads to more difficult to manage code.<br>
> <br>
> If we fail to teach the language properly we start on a slippery slope to<br>
> duplication (which is an awful evil, leading to much increased maintennance<br>
> effort, and brittleness), and rendering perfectly good, well thought-out<br>
> idioms mysterious.  It;'s not like Smalltalk has a lot of rules; the<br>
> number, compared to C & C++ et al is tiny.  And terseness has not just<br>
> aesthetic benefit, but real practical benefit in terms of readability &<br>
> maintainability.<br>
> <br>
> > Also, with this change, the compiler leaks the default value of any<br>
> > temporary variable, which we previously were able to hide at least<br>
> > partially.<br>
> ><br>
> ><br>
> But that is a MISTAKE!! The language designers didn't arrange for temps to<br>
> be initialized to nil just because that's the only default.  They did it to<br>
> ensure that there is no such thing as an  uninitialized variable in<br>
> Smalltalk.  That's why nil ids an object, with a class, not just nil.<br>
> That's why nil ~~ false.  It's carefully thought out and not just some<br>
> artifact of the implementation.  And that rationale (read the blue book<br>
> carefully) and its implications, should be taught/learned/known, and<br>
> especially exemplified by the core code of Squeak trunk, and hence<br>
> supported by the compiler.<br>
> <br>
> > In many cases, I think explicitly setting a temporary variable to nil<br>
> > before it is initialized within some non-trivial conditional complex would<br>
> > be more explicit, thus more readable, and something which we should<br>
> > generally encourage programmers to do.<br>
> ><br>
> ><br>
> I disagree.  You're advocating for absurdities such as<br>
> <br>
>     | colors |<br>
>     colors :=- ColorArray new: 256.<br>
>     colors atAllPut: Color transparent<br>
> <br>
> This is the kind of thinking that leads to cycling wearing American<br>
> Football clothes.  It won't keep you from being run over by a truck, but<br>
> it'll make you so slow and reduce your peripheral vision so much, not to<br>
> mention give you a false sense of security, that you'll be much more likely<br>
> to be run over by a truck...<br>
> <br>
> > Looking forward to your opinion!<br>
> ><br>
> ><br>
> :-)  Hope I'm not too strident :-)<br>
> <br>
> > Best,<br>
> ><br>
> > Christoph<br>
> > ------------------------------<br>
> > *Von:* Squeak-dev <squeak-dev-bounces at <a href="http://lists.squeakfoundation.org" target="_blank">lists.squeakfoundation.org</a>> im<br>
> > Auftrag von commits at <a href="http://source.squeak.org" target="_blank">source.squeak.org</a> <commits at <a href="http://source.squeak.org" target="_blank">source.squeak.org</a>><br>
> > *Gesendet:* Mittwoch, 23. November 2022 04:10:30<br>
> > *An:* squeak-dev at <a href="http://lists.squeakfoundation.org" target="_blank">lists.squeakfoundation.org</a>;<br>
> > packages at <a href="http://lists.squeakfoundation.org" target="_blank">lists.squeakfoundation.org</a><br>
> > *Betreff:* [squeak-dev] The Trunk: Compiler-eem.480.mcz<br>
> ><br>
> > Eliot Miranda uploaded a new version of Compiler to project The Trunk:<br>
> > <a href="http://source.squeak.org/trunk/Compiler-eem.480.mcz" target="_blank">http://source.squeak.org/trunk/Compiler-eem.480.mcz</a><br>
> ><br>
> > ==================== Summary ====================<br>
> ><br>
> > Name: Compiler-eem.480<br>
> > Author: eem<br>
> > Time: 22 November 2022, 7:10:27.324796 pm<br>
> > UUID: 3e5ba19e-c44a-4390-9004-de1246736cbc<br>
> > Ancestors: Compiler-eem.479<br>
> ><br>
> > Do not warn of an uninitialized temporary if it is being sent ifNil: or<br>
> > ifNotNil:.<br>
> ><br>
> > =============== Diff against Compiler-eem.479 ===============<br>
> ><br>
> > Item was changed:<br>
> >   ----- Method: Parser>>primaryExpression (in category 'expression types')<br>
> > -----<br>
> >   primaryExpression<br>
> >          hereType == #word<br>
> >                  ifTrue:<br>
> >                          [parseNode := self variable.<br>
> > +                        (parseNode isUndefTemp<br>
> > +                         and: [(#('ifNil:' 'ifNotNil:') includes: here)<br>
> > not<br>
> > +                         and: [self interactive]])<br>
> > +                                ifTrue:<br>
> > +                                        [self queryUndefined].<br>
> > -                        (parseNode isUndefTemp and: [self interactive])<br>
> > -                                ifTrue: [self queryUndefined].<br>
> >                          parseNode nowHasRef.<br>
> >                          ^ true].<br>
> >          hereType == #leftBracket<br>
> >                  ifTrue:<br>
> >                          [self advance.<br>
> >                          self blockExpression.<br>
> >                          ^true].<br>
> >          hereType == #leftBrace<br>
> >                  ifTrue:<br>
> >                          [self braceExpression.<br>
> >                          ^true].<br>
> >          hereType == #leftParenthesis<br>
> >                  ifTrue:<br>
> >                          [self advance.<br>
> >                          self expression ifFalse: [^self expected:<br>
> > 'expression'].<br>
> >                          (self match: #rightParenthesis)<br>
> >                                  ifFalse: [^self expected: 'right<br>
> > parenthesis'].<br>
> >                          ^true].<br>
> >          (hereType == #string or: [hereType == #number or: [hereType ==<br>
> > #literal or: [hereType == #character]]])<br>
> >                  ifTrue:<br>
> >                          [parseNode := encoder encodeLiteral: self advance.<br>
> >                          ^true].<br>
> >          (here == #- and: [tokenType == #number and: [1 + hereEnd = mark]])<br>
> >                  ifTrue:<br>
> >                          [self advance.<br>
> >                          parseNode := encoder encodeLiteral: self advance<br>
> > negated.<br>
> >                          ^true].<br>
> >          ^false!<br>
> ><br>
> _,,,^..^,,,_<br>
> best, Eliot<br>
> -------------- next part --------------<br>
> An HTML attachment was scrubbed...<br>
> URL: <<a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20221123/dfd355fa/attachment.html" target="_blank">http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20221123/dfd355fa/attachment.html</a>><br></blockquote></div><div><br></div><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div>