Going back to Dec 3rd explanation:
"... I had a chain of methods which should do some side effect.
It all went fine only the side effect was not there. I then figured
out after some time that one of methods returned Nil and
somehow silently it did not do what I expected."
This looks like an incomplete set of rules – an API contract that needs
filling in – more than a language issue. From the illustrative example now
in play
$drone.engine.start;
the original code as described in the Dec 3rd extract above, implies these
rules:
Each method
- has a side effect on success, no side effect on failure.
- returns a defined object on success. return behavior on failure not
explicitly defined.
Expectation- failure should show more than lack of side effects plus Nil
return value at final step.
Now if all of the "$drone" object/class, the "engine" method, and the
"start" method are app code, then we can fill out the contract so that
$drone.engine.start does the right thing. If on the other hand it was a
Rakudo call which returned Nil instead of failing, then there is a language
issue. Which is what E.M. posted on Dec 3rd:
Nil is really a Failure that doesn't throw. It indicates the absence of a
> value where there is one expected.
> That is why Nil doesn't throw. If you want to indicate a soft failure,
> you should use fail().
> If the chain of methods you mention are core methods, and one of them is
> returning Nil, then perhaps we have a bug. Could you elaborate on the
> situation where you encountered this?
For the sake of discussion, let's fill out the contract each method adheres
to. Side effect has no change
- has a side effect on success, no side effect on failure.
To fulfill the expectation that a failure anywhere "shows up" early, there
are a few tweaks available.
1. On failure, method throws an exception/"die"s -
https://docs.raku.org/language/exceptions
2. On failure, method returns an failure object -
https://docs.raku.org/type/Failure
3. Methods never return Nil. - requires a little work to check at the
returns.
Any of those will make a failure show up closer to where it happened.
I can only recommend #3 in the case where there must be an engine.
A slight modification to the example can show why a method may want to
return Nil on success, and also show that the behavior of Nil with method
calls is actually rather useful:
$drone.wheels.lock;
If a drone has no wheels, the "wheels" method returns Nil and the code
still works. For a drone with wheels, it can throw an exception or return a
failure if there's a problem with the "wheels" method– or if the brakes
don't work, then "lock" can die or return a failure.
-y
On Fri, Dec 18, 2020 at 12:58 PM Konrad Bucheli via perl6-users <
[email protected]> wrote:
>
>
> On 16.12.20 12:39, Brad Gilbert wrote:
> > with $drone.engine {
> > .start;
> > say "engine started";
> > }
>
> Now we get the inverse pyramid of doom. Above code does not the same as
> mine, it only improves the debugging output, but does not fail:
>
> with $drone.engine {
> .start;
> say "engine started";
> }
> orelse {
> die "looks like we lost the engine";
> }
>
> My point is that I never expected the engine to be lost, because it is
> an integral part of the drone. And that is correct because it was only a
> bug in `engine` which was revealed during testing and when fixed I do
> not need all this any more.
>
> So to understand all the implications of
>
> $drone.engine.start;
>
> I need in depth Raku understanding. Is that already tribal knowledge?.
> Or you have already been hurt by it as I was. It is definitively not
> beginner friendly and not even intermediate friendly.
>
> I feel uncomfortable with that. Whenever I see something like this I
> have to be aware that the normally obvious assumptions are incorrect.
> These bugs are more difficult to find because the program continues and
> only later on you will see that some data or state is incorrect. And the
> problem with incorrect data is that you might not even spot it.
>
>
> >
> > On Tue, Dec 15, 2020, 11:10 PM Konrad Bucheli via perl6-users
> > <[email protected] <mailto:[email protected]>> wrote:
> >
> >
> > Hi Ralph
> >
> > Thanks a lot for the extensive answer.
> >
> > I still consider it a trap because it does not do what it tells it
> does.
> >
> > If I have:
> >
> > say "launching drone";
> > $drone.engine.start;
> > say "engine started";
> >
> > After I run the above I got both messages, but no propeller
> > spinning. So I checked start() in and out, because that is where the
> > problem is obviously.
> > But it was not, it was in engine().
> > And I want my programming language/runtime to tell me if I am doing
> > obviously stupid things.
> > Note that it has nothing to do with the "pyramid of doom". It would
> > make sense in a pure functional environment, but Raku is
> > multi-paradigm, no?
> >
> > Now to be "safe" (as in fail fast) I have to always
> >
> > say "launching drone";
> > # this intermediate variable is important defensive programming,
> > else it will not explode on Nil if there are stupid errors in
> engine()
> > my $engine = $drone.engine;
> > $engine.start;
> > say "engine started";
> >
> > which is the opposite of concise.
> >
> > But Raku is Raku, there is surely a way to make sure that my Nil
> > explodes in my code. Is there a `use FailingNil`?
> >
> > Concerning documentation: I do not know where there is an
> > appropriate place to warn about this behavior. There where we teach
> > how methods are called? Surely it would not have found me. I look up
> > a lot in documentation, but not such trivial stuff.
> >
> > Cheers
> >
> > Konrad
> >
> > From: Ralph Mellor <[email protected]
> > <mailto:[email protected]>>
> > Sent: Saturday, 5 December 2020 15:58
> > To: Konrad Bucheli <[email protected]
> > <mailto:[email protected]>>
> > Cc: perl6-users <[email protected] <mailto:[email protected]>>
> > Subject: Re: Missing NullPointerException
> >
> > On Thu, Dec 3, 2020 at 10:20 PM Konrad Bucheli via perl6-users
> > <[email protected] <mailto:[email protected]>> wrote:
> > >
> > > What is actually the rationale for such a behaviour?
> >
> > Ergonomically sound null safety.
> >
> > First, consider what other languages have. Quoting
> > https://en.wikipedia.org/wiki/Safe_navigation_operator
> > <https://en.wikipedia.org/wiki/Safe_navigation_operator>:
> >
> > > In object-oriented programming, the safe navigation operator
> > > ... is used to avoid sequential explicit null checks ...
> > ...
> > > In programming languages where the navigation operator
> > > (e.g. ".") leads to an error if applied to a null object, the safe
> > > navigation operator stops the evaluation of a method/field
> > > chain and returns null as the value of the chain expression.
> > ...
> > > It is currently supported in languages such as Apex, Groovy,
> > > Swift, Ruby, C#, Kotlin, CoffeeScript, Scala, Dart and others.
> > ...
> > > The main advantage of using this operator is that it avoids the
> > > pyramid of doom. ...
> >
> > Many aspects of Raku's design are better solutions than are found
> > in older PLs like those listed above. This is an example. Instead of
> > devs having unsafe operations by default, and having to write `?.`
> > to get safety, in Raku one just writes `.` and always gets safety.
> >
> > > For me it was an unexpected trap
> >
> > This statement couples deep wisdom (the "for me" qualification,,
> > deferring it till after you'd first asked about what the rationale
> was,
> > and sharing your experience) with a Canby.[1]
> >
> > It's clear that you were missing some knowledge, and that it
> > bit you, and are now exploring how best to learn from that.
> >
> > I accept without reservation the claim it was "unexpected". (That
> > is the sort of thing that is typically experienced and reported by
> > request of our right hemispheres, and it is generally reliable.)
> >
> > I also recognize what I imagine as a negative effect associated
> > with classifying this experience / situation as a "trap", and the
> > negative affect associated with applying that classification, which
> > is to say your right hemisphere's experience of that classification.
> >
> > With that said, I now wish to engage our respective unreliable
> > left hemispheres, the ones that drive classification, and wish to
> > suggest another way to view this situation.
> >
> > I would argue that you are classifying safe navigation as a trap,
> > and thus likely experiencing it negatively. Perhaps for you this
> > can/will instead become a gift (perhaps also unexpected)?
> >
> > A fundamental part of human experience is interpreting one's
> > reactions to things in the light of further knowledge and/or
> > experience. Larry has made it clear to me that this is one of
> > the keys to his approach to life, and to PL design, in both the
> > sense of how he approaches a PL's design and how the PL's
> > designed features reward those who think the same way. (I
> > have found this endlessly inspiring.)
> >
> > Applying that to your experience, you could alternately view
> > what happened as a surprise that arises from Raku's default
> > of safety, which is about freedom (avoiding both the extensive
> > boilerplate of the pyramid of doom, and the modern shorter
> > but still boilerplate additional ?), and not, it could reasonably
> > be argued, about a trap.
> >
> > cf my discussion of what Vadim Belman had classified as a WAT in
> >
> https://www.nntp.perl.org/group/perl.perl6.users/2018/09/msg5418.html?mc_phishing_protection_id=45408-bvcv3ppeg2buflbq1e30
> > <
> https://www.nntp.perl.org/group/perl.perl6.users/2018/09/msg5418.html?mc_phishing_protection_id=45408-bvcv3ppeg2buflbq1e30
> >
> >
> > > It all went fine only the side effect was not there. I then
> figured
> > > out after some time that one of methods returned Nil and
> > > somehow silently it did not do what I expected.
> >
> > The "somehow" was automatic safe navigation, By definition,
> > this is silent as far as it goes.
> >
> > But if you think about it, it wasn't *entirely* silent. You knew
> > *something* wasn't working right, because somewhere you
> > expected a value and didn't get one. So you then had to go
> > chase that down.
> >
> > This is another pervasive principle in Larry's design approach.
> > If a PL tries too hard to avoid programming errors, it becomes
> > a police state. If it ignores the potential for programming errors
> > it forgets to introduce things like safe navigation by default.
> >
> > The sweetspot is a balance between trade offs that overall
> > lets devs reasonably easily "get" working code (in both the
> > sense of arriving at it when writing, and comprehending it
> > when reading), and keep making progress in the event of
> > things not working out as expected.
> >
> > I see signs that Raku gets that right a lot of the time for me,
> > and for others I see using and discussing it, and that the
> > culture is generally agreeably open to figuring out whether
> > any given negative experiences are best left as something
> > for individual involved devs to adapt to, or as necessitating
> > improvements in the doc, or Raku, or Rakudo, or modules etc
> >
> > And at the foundation of it all, is our open minded but also
> > mindful right hemispheres, which it's clear we all share.
> >
> > Which leads me to a concluding question.
> >
> > Given your own reflections on the rationale I have described,
> > and perhaps the wisdom that comes when we "sleep on it",
> > is your conclusion that it would be best if there were some
> > change in the doc, or Raku, or Rakudo, etc., or does it make
> > enough sense now that it was, in the final analysis, really
> > just unexpected rather than also being a trap?
> >
> > love, raiph
> >
> > [1]
> >
> http://quotegeek.com/literature/norton-juster/the-phantom-tollbooth/3184/?mc_phishing_protection_id=45408-bvcv3ppeg2buflbq1e30
> > <
> http://quotegeek.com/literature/norton-juster/the-phantom-tollbooth/3184/?mc_phishing_protection_id=45408-bvcv3ppeg2buflbq1e30
> >
> >
>
> --
> Konrad Bucheli
> Systems Engineering Fellow
>
> O. +41 58 100 10 10
> W. open-systems.com
>
> Open Systems
>
>