<div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small">Hi Tobi,<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Nov 24, 2022 at 12:18 PM Tobias Pape <<a href="mailto:Das.Linux@gmx.de">Das.Linux@gmx.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>
First things first, I did not raise objections in my admittedly short quip.<br>
<br>
<br>
> On 24. Nov 2022, at 20:23, Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>> wrote:<br>
> <br>
> Hi Tobi,<br>
> <br>
>     let me try again (<a href="https://youtu.be/Cj8n4MfhjUc)" rel="noreferrer" target="_blank">https://youtu.be/Cj8n4MfhjUc)</a>…<br>
<br>
:D <br>
<br>
I already got my comfy chair!<br>
<br>
> <br>
>> On Nov 23, 2022, at 12:23 PM, Tobias Pape <<a href="mailto:Das.Linux@gmx.de" target="_blank">Das.Linux@gmx.de</a>> wrote:<br>
>> <br>
>> Yet, nil is only seldom a good domain object.<br>
> <br>
> Precisely. Being disjoint from any domain it is the ideal “I am not a domain object” marker. So when one wants a variable to range over a domain and the singleton “not a member of the domain” nil is a great choice.  And that’s exactly how I use it below.<br>
<br>
Second things second, I got that.<br>
<br>
> <br>
> There is another excellent marker of a non-domain object, and that is a newly instantiated object. That object is known to not be any other object, since objects are unique.  So if code is searching for something (eg applying a block to every literal in the system), having the newly instantiated object that implements the search use itself as the “I’m not in the domain of all pre-existing objects” is a sensible choice.  This is the pattern InstructionStream uses when scanning for selectors.<br>
<br>
And #someObject/#nextObject.<br>
I get that. And it is actually a beautiful thing you cannot do everywhere[0].<br>
<br>
My fear is as follows:<br>
<br>
I hope we can agree that "nil" is part of the "system domain" of Smalltalk, or - said differently - the meta-level.<br>
<br>
So are the concepts of variables, classes etc. <br></blockquote><div> </div><div class="gmail_default" style="font-size:small">Yes, and equally, for example, collections. The Set instance in a set of accounts is not part of the domain because it's not specific to the domain.  It comes from the Smalltalk library.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">But so what?  This feels like a straw man to me.  One could argue that an account object itself is not part of the domain, but part of the model of the domain, etc.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">In the end nil is an object that is useful and well-defined.  It isn't special, just like true & false aren;t special, or that classes being objects aren't special.  Instead these are all functional relationships that allow us to construct a system that is malleable and comprehensible.</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>
The non-meta, base, or "domain proper" layer can be anything you want to computationally achieve.[1]<br>
Let's arbitrarily chose finance[2].<br>
<br>
A domain object would be an account, a transaction, an account holder, etc.<br>
(Note that we can chose how to represent each, and we do not necessarily need objects for each, but I digress).<br>
<br>
My take: in code dealing with such domain objects, nil should appear next to never, because it is an object from the Metalevel.<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">I don't agree. nil can serve as an absence, and absences are important.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">In any query which can yield no results we have three choices:</div><div class="gmail_default" style="font-size:small">- answer nil (e.g. at end of stream)</div><div class="gmail_default" style="font-size:small">- raise an exception</div><div class="gmail_default" style="font-size:small">- require passing in a continuation to take in the event of an error (e.g. the block argument to at:ifAbsent: or the second one to detect:ifNone: etc)</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">Often nil is lighter-weight, much more concise, and hence more comprehensible, hence to be preferred.</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">The problems with accepting nil as the general "nothing to see" marker include:<br>
<br>
- There are too many.<br>
  In our example, an account holder could have an instVar "account" which could be nil when not having an account yet, BUT ALSO<br>
  an account could have a "closingDate" for when the account folded, which is "nil" when the account is still open, AND ALSO, a transaction could have<br>
  an "auditor" which is nil as long as no audit has taken place etc. <br>
    Just like that, nil takes _different roles_ just by being convenient.<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">As do the integers, symbols, collections. As do classes.  Should we have different kinds of classes for the class library, the meta level, the domain model? Or is it sufficient to have classes, metaclasses and traits?  i.e. do we need to label things according to their use, or is it sufficient to differentiate them purely by function?  I think the latter.</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">- Nil has problematic provenance.<br>
  When somewhere during debugging (the all-known MNU for UndefinedObject) a nil pops up, it is often reallllly hard to say whence it came from.<br>
    So dealing with a lot of nil-bearing code will send you down rabbit holes after the other.<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">Whereas NaN doesn't have problematical provenance?  Or getting an identically-valued instance with a different identity, or a host of other potential evils.... These are not specific to nil, and not specific to using nuil as a marker of absence, or as bottom.  Programming is tricky; we have lots of ways of doping things; things happen very fast; code does what tou tell it, not what you want it to do.  We find we make mistakes all the time.  This is not specific to the use of nil in our domain models.</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">- Nil begets polymorphism, nil defies polymorphism.<br>
  It is one of the most awesome feats of Smalltalk that nil is NOT like NULL, in that it can respond to messages. That is exceptionally powerful<br>
  and has given Smalltalk a lot of resilience.<br>
   But cluttering UndefinedObject with custom, even domain-specifc methods is a really bad idea. However, that means<br>
  it is often unwise to just have object that could be nil be sent arbitrary messages.<br>
  Hence a multitude of #isNil/#ifNil-Checks. Proper domain objects that model absence, pre-valid state, or error conditions can deal much better with that.<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">When it's possible then fine.  But in the query example above we must be able to deal with absence/have an element disjoint from a domain.  And nil functions ideally for this case.</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">- Nil is in a collection-superposition (just like your good old USB-A plug which you have to turn at least twice to fit).<br>
  You only know whether nil _actually_ could be a collection when you know that a non-nil object in its place is a collection [3].<br>
  Said differently: in contrast to LISPy languages, our nil is _by design_ no collection, while LISPy null _by design_ IS the empty list.<br>
  This makes for funny messages like #isEmptyOrNil, which bails on non-nil-non-collection objects.<br>
    So every time you have to deal with nil, you automatically at lease once have to answer the question "could the non-nil version of this object be a collection"?<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">Many uses of isEmptyOrNil are in response to FillInTheBlank which can return nil on cancel or an empty string if the user doesn't type anything.  This is a natural consequence of the affordances of FillInTheBlank, and isEmptyOrNil is simply a pragmatic response, hardly a symptom of some deep problem.</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>
There are a lot of interesting approaches to each or combinations of these issues.<br>
This includes Null-Object patterns, Sane-default-initializers, exceptions, or explicit models of multiplicity[4].<br>
<br>
But back to the beginning.<br>
<br>
In code that does, for example<br>
<br>
blaFooAnAccount<br>
<br>
  | fooAccount |<br>
  self accounts processBla: <br>
    [:ea |<br>
    fooAccount ifNil: [fooAccount := ea].<br>
    fooAccount := (ea doesBork: fooAccount)<br>
      ifTrue: [fooAccount]<br>
      ifFalse: [ea]]<br>
  ^ fooAccount<br>
<br>
we find two things:<br></blockquote><div><br></div><div class="gmail_default" style="font-size:small">I think we find three things. The things you8 list below, plus the fact that this should have been written using detect:ifNone: ;-)</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>
First, we could inadvertently return nil from that method. But this is technical and I think most here can deal with that.<br>
<br>
But second, the line "fooAccount ifNil: [fooAccount := ea]." ACTUALLY says<br>
<br>
  "if fooAccount is an uninitialized temporary variable, populate it".<br>
<br>
This is technically correct, but conflates domains.<br>
In our world of finance, the idea of a "temporary variable" does no make sense. It is part of the meta-level domain, the system.<br>
<br>
I don't say this is wrong _per se_ but people reading, and even more so, people writing such code <br>
MUST be aware that they are crossing domains, and especially, entering a meta level.<br>
<br>
That's why I think these warnings are really ok.<br>
I won't fight the commit "Compiler-eem.480.mcz", especially since it more or less is descriptive of a pervasive style of writing Smalltalk of Squeak Core contributors.<br>
<br>
I hope people find theses ideas useful.<br>
<br>
Best regards<br>
        -Tobias<br>
<br>
<br>
[0]: I've used it in Python code to much joy.<br>
[1]: Caveat lector: the "domain layer" can surely be the "system layer". In fact that is what a lot of system code deals with. <br>
     But this is messy for our considerations above and lets treat it as _exceptional_.<br>
[2]: Semi-arbitrarly, just because I received my tax returns :P<br>
[3]: yes, that is a strange sentence. It's late. Also, Ardbeg.<br>
[4]: For example, as in the work of Steimann (<a href="https://dl.acm.org/doi/10.1145/2509578.2509582" rel="noreferrer" target="_blank">https://dl.acm.org/doi/10.1145/2509578.2509582</a> ). It seems they had a Smalltalk implementation in 2017.<br>
<br>
<br>
> <br>
>> -t<br>
>> <br>
>>> On 23. Nov 2022, at 19:34, tim Rowledge <<a href="mailto:tim@rowledge.org" target="_blank">tim@rowledge.org</a>> wrote:<br>
>>> <br>
>>> I won't quote it all again but what Eliot wrote is important. There are good solid reasons why Smalltalk has a rigorously defined UndefinedObject. We demand rigorously defined areas of doubt and uncertainty!<br>
>>> <br>
>>> tim<br>
> <br>
> <br>
> _,,,^..^,,,_ (phone)<br>
> <br>
<br>
<br>
<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><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>