Re: Missing NullPointerException

2020-12-18 Thread Konrad Bucheli via perl6-users



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 
mailto:perl6-users@perl.org>> 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 mailto:ralphdjmel...@gmail.com>>
Sent: Saturday, 5 December 2020 15:58
To: Konrad Bucheli mailto:kbuch...@open-systems.com>>
Cc: perl6-users mailto:perl6-users@perl.org>>
Subject: Re: Missing NullPointerException

On Thu, Dec 3, 2020 at 10:20 PM Konrad Bucheli via perl6-users
mailto:perl6-users@perl.org>> 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 

Re: Missing NullPointerException

2020-12-18 Thread Konrad Bucheli via perl6-users

Hi Ralph

I understand that this is about avoiding the pyramid of doom.
And it is enjoyable that it can be avoided. Opt in.

No programming language I worked so far has this semantics of method 
call. So we might name it differently as it is doing something 
different... -> that is the trap.
(I am aware that it is not different, it is only the Nil class which 
makes it look different)


But now I cannot even opt out without creating an "inverse pyramid of 
doom".


It is "optimized" for one common use case (navigation) but makes another 
common use case (creating side effects) unexpectedly and surprisingly 
harder.


IMHO this medicine is worse than the illness. I consider a safe 
navigation operator would be a more balanced.


In my case it would would probably have helped if

return;

would return a Failure, not Nil. Maybe we need a warning on top of the 
Nil documentation: you might be better off with a Failure...


Cheers
Konrad

On 17.12.20 23:07, Ralph Mellor wrote:

On Wed, Dec 16, 2020 at 5:10 AM Konrad Bucheli ... wrote:


there is surely a way to make sure that my Nil
explodes in my code. Is there a `use FailingNil`?


I'd +1 a `use fatal :Nil;`.



In the meantime, this appears to work:

```
engine.?Raptor::start
```

Might be a bug because an *unqualified* call failure is silent:

```
engine.?start
```

Perhaps it's deliberate that if you qualify you make it fail fast?

But it might also be considered a bug. I haven't investigated.



Perhaps also a fail fast version that doesn't require a `use fatal`
or qualified method but just a different method call op.

And perhaps it is better than just making `foo.?bar` fail if there is
no `bar` method on `Nil`. Perhaps it always fails if the invocant is
`Nil` or `Failure` no matter what the method name is? So even
`Nil.Str` or `Nil.FALLBACK` fail?



Bikeshedding syntax:

```
engine.?!start.
```


Note that it has nothing to do with the "pyramid of doom".


When you say "it", what is "it"?

I get that your surprise, and your perspective that `.` doesn't
do what it says it does, and the feeling of a trap, are nothing to
do with the pyramid of doom.

But the reason why Raku's `.` is the way it is is in large part due
to the issue referred to on Wikipedia as "the pyramid of doom",
and the desire to have the default method call operator avoid it,
because that's in keeping with Raku's philosophy of soft failure
as the general default approach, with `Nil` as a benign `Failure`.

If calling a method on `Nil` immediately threw, the whole notion
of `Nil` as a benign `Failure` would, well, fail.


  it does not do what it tells it does.


`foo.bar` does what it tells me it does:

* Try to call method `bar` on `foo`.

* If it fails to resolve on a non-failure, fail fast.

* If it fails to resolve on a benign failure, keep it benign.

If you *don't* accept that what `.` does is explicitly avoid
the pyramid of doom, then that begs two questions:

* What do you think the pyramid of doom is?

* What about Raku's `.` fails to avoid the pyramid of doom?


Now to be "safe" (as in fail fast) I have to always...


If you define "safe" as "fail fast" and reject "safe navigation" as
being "safe", then fair enough.

Perhaps you prefer a default in a PL of strong static typing?

(I like strong static typing, and fail fast, and things like that,
and hope to see folk one day create pragmas that do things
like turning coercions off en masse in a lexical scope or `use
fatal :Nil;`. But I also like weak dynamic typing, benign failure
modes, and safe navigation by default too.)


Concerning documentation: I do not know where there is an
appropriate place to warn about this behavior.


Me neither.

Part of the issue with PLs is that many programmers getting
to know a new PL not only tend to have expectations based
on PLs they have already had experience with, but also tend
to classify surprises that bite them, when that surprising thing
would not occur in PLs they're used to, as something that, at
least from their perspective, is a trap.

And I do wonder if that's part of what's going on in this case.

And, even if it is, they're still right from their perspective. In
which case, in some senses, perhaps such things ought to
be loudly flagged somewhere in Raku's doc in a manner that
will be likely to be seen by others who share their experience.

Perhaps in a section dedicated to going from some other
specific PL(s) to Raku, presumably the nutshell pages.

Or maybe it's reasonable to also have PL specific trap pages,
distinct from the nutshell pages (even if linked from them), and
perhaps precursors to them.

If so, a natural person to start those would presumably be someone
like yourself who experiences the trap.

Or maybe things like this belong on the already existing single
*general* Traps page?


There where we teach how methods are called? Surely it
would not have found me.


Right. Things like that just makes this thornier.

Have you read the general Traps 

Re: Missing NullPointerException

2020-12-15 Thread Konrad Bucheli via perl6-users

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 
Sent: Saturday, 5 December 2020 15:58
To: Konrad Bucheli 
Cc: perl6-users 
Subject: Re: Missing NullPointerException 
 
On Thu, Dec 3, 2020 at 10:20 PM Konrad Bucheli via perl6-users
 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:

> 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

> 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.

T

Re: Missing NullPointerException

2020-12-05 Thread Konrad Bucheli via perl6-users
The returned Nil aka bug was from my side. But when debugging it took me 
a while to find the culprit because when the statement with the chained 
methods was executed I expected all of them being executed...


So that was a bit of a surprise.

Thanks for the insights!

On 03.12.20 23:25, Elizabeth Mattijsen wrote:

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?


On 3 Dec 2020, at 15:22, Konrad Bucheli via perl6-users  
wrote:



On 02.12.20 15:55, Ralph Mellor wrote:

On Wed, Dec 2, 2020 at 7:08 AM Patrick R. Michaud  wrote:

Nil.any_non_existent method always seems to return Nil.  I'm not sure where 
this is documented

It's near the top of the `Nil` doc page you linked:

Any method call on `Nil` of a method that does not exist ... will succeed and 
return `Nil`.



OK, that is intentional and documented then. What is actually the rationale for 
such a behaviour?

For me it was an unexpected trap as 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.

Thanks

Konrad



--
Konrad Bucheli
Systems Engineering Fellow

O.  +41 58 100 10 10
W.  open-systems.com

Open Systems



smime.p7s
Description: S/MIME Cryptographic Signature


No such method 'prefix' for invocant of type 'Capture' when trying to patch a new library include path

2020-05-10 Thread Konrad Bucheli via perl6-users
Dear Raku experts


I have a little patch which adds another library include path and installation 
site named "foo" which points to "/opt/foo/lib", see attached patch.

That worked (in a similar fashion) well with 2020.02, but with 2020.05 it fails 
on the following test:


$ cat foo.rakumod
unit module foo;
use Test;
$ raku -I . -e "use foo"
===SORRY!=== Error while compiling -e
===SORRY!=== Error while compiling /home/kb/foo.rakumod (foo)
No such method 'prefix' for invocant of type 'Capture'
at /home/kb/foo.rakumod (foo):2

at -e:1
$


Interestingly it works fine after the second or third time, and then always, 
until I remove the ~/.raku and .precomp directories...

Maybe it is fine when it somehow managed to get precompiled. And without this 
little innocent patch it is also working.

Can someone enlighten me?

Cheers

Konrad
diff --git a/src/core.c/CompUnit/RepositoryRegistry.pm6 b/src/core.c/CompUnit/RepositoryRegistry.pm6
index 84250e72e..26274464e 100644
--- a/src/core.c/CompUnit/RepositoryRegistry.pm6
+++ b/src/core.c/CompUnit/RepositoryRegistry.pm6
@@ -136,6 +136,7 @@ class CompUnit::RepositoryRegistry {
 my str $core   = 'inst#' ~ $prefix ~ $sep ~ 'core';
 my str $vendor = 'inst#' ~ $prefix ~ $sep ~ 'vendor';
 my str $site   = 'inst#' ~ $prefix ~ $sep ~ 'site';
+my str $foo= 'inst#' ~ '/opt/foo/lib';
 
 my str $home;
 my str $home-spec;
@@ -182,6 +183,17 @@ class CompUnit::RepositoryRegistry {
   )
 ) unless nqp::existskey($unique, $site);
 
+# FOO specific: /opt/foo/lib
+nqp::bindkey($custom-lib, 'foo',
+  $next-repo := self!register-repository(
+$foo,
+CompUnit::Repository::Installation.new(
+  :prefix('/opt/foo/lib'),
+  :$next-repo
+)
+  )
+) unless nqp::existskey($unique, $foo);
+
 nqp::bindkey($custom-lib,'home',
   $next-repo := self!register-repository(
 $home-spec,
@@ -215,6 +227,11 @@ class CompUnit::RepositoryRegistry {
 my \repo := nqp::atkey($repos,$site);
 nqp::bindkey($custom-lib,'site',repo) if repo;
 }
+# FOO specific: /opt/foo/lib
+unless nqp::existskey($custom-lib, 'foo') {
+my \repo := nqp::atkey($repos, $foo);
+nqp::bindkey($custom-lib, 'foo', \repo) if repo;
+}
 unless nqp::existskey($custom-lib,'home') {
 if $home-spec {
 my \repo := nqp::atkey($repos,$home-spec);


unflattering flat

2020-04-03 Thread Konrad Bucheli via perl6-users
Dear Raku programmers

I have a hash with arrays as value. Out of that I wanted to get a flat list 
with all the entries in the value arrays. My first intuitive attempt was to use 
flat, but somehow that only works with an additional map step:

 $ raku
To exit type 'exit' or '^D'
> my %hash-with-arrays = a => [1,2], b => [2,3]
{a => [1 2], b => [2 3]}
> %hash-with-arrays.values.flat
([2 3] [1 2])
> %hash-with-arrays.values>>.map({$_})
((2 3) (1 2))
> %hash-with-arrays.values>>.map({$_}).flat
(2 3 1 2)
> 
$ raku -v
This is Rakudo version 2020.02 built on MoarVM version 2020.02
implementing Raku 6.d.
$ 

How is that explained?

Cheers

Konrad

AW: MoarVM panic when using PKafka

2019-03-28 Thread Konrad Bucheli via perl6-users
Sorry, I forgot about


# perl6 -v
This is Rakudo version 2019.03.1 built on MoarVM version 2019.03
implementing Perl 6.d.



Von: Konrad Bucheli via perl6-users 
Gesendet: Donnerstag, 28. März 2019 15:36
An: perl6-users
Betreff: MoarVM panic when using PKafka

Hi

We want to use Perl 6 as Kafka client. When I want to save the offset in
the queue after I processed the message I get some MoarVM panics:

 MoarVM panic: Internal error: zeroed target thread ID in work pass

or sometimes

 MoarVM panic: Internal error: invalid thread ID 8614688 in GC work pass

This only happens after running it for some time (< 1 minute)
Code below:

use PKafka::Consumer;
use PKafka::Message;
use PKafka::Config;

sub MAIN () {
my $exception-channel = Channel.new;
for (0..5) -> $partition {

say "start $partition";

my $kafka-config = PKafka::Config.new({
'metadata.broker.list' => 'kafka-dev-1:5551,
kafka-dev-2:5551, kafka-dev-3:5551',
'security.protocol' => 'ssl',
'ssl.ca.location' => '/etc/ssl/ca_server_cert.pem',
'ssl.certificate.location' => '/etc/ssl/client_cert.pem',
'ssl.key.location' => '/etc/ssl/client_key.pem',
'ssl.key.password' => 'password',
'group.id' => 'metrics-feed-consumer',
'enable.auto.offset.store' => 'false',
});
my $kafka-consumer = PKafka::Consumer.new(
 topic => 'monitoring.metrics', brokers =>
'kafka-dev-1:5551, kafka-dev-2:5551, kafka-dev-3:5551',
 config => $kafka-config
);
$kafka-consumer.messages.tap(-> $msg {
given $msg {
when PKafka::Message {
say "$partition : got {$msg.payload-str}";
$kafka-consumer.save-offset($msg); # <--- guilty line
}
}
});

my $worker-done = $kafka-consumer.consume-from-last(partition =>
$partition);

$exception-channel.send($worker-done);
}

react {
# handle exceptions
whenever $exception-channel -> $promise {
whenever $promise {}
}

# fininsh up properly with signals
whenever signal(SIGINT,SIGKILL) { done }
}
}


 end of code

Could that an MoarVM issue? Could it be some threading issue withing
librdkafka? Or in the interaction between both?


Cheers
Konrad


--
konrad bucheli
principal systems engineer

open systems ag
raeffelstrasse 29
ch-8045 zurich

t: +41 58 100 10 10
f: +41 58 100 10 11
k...@open.ch

http://www.open.ch



MoarVM panic when using PKafka

2019-03-28 Thread Konrad Bucheli via perl6-users

Hi

We want to use Perl 6 as Kafka client. When I want to save the offset in 
the queue after I processed the message I get some MoarVM panics:


MoarVM panic: Internal error: zeroed target thread ID in work pass

or sometimes

MoarVM panic: Internal error: invalid thread ID 8614688 in GC work pass

This only happens after running it for some time (< 1 minute)
Code below:

use PKafka::Consumer;
use PKafka::Message;
use PKafka::Config;

sub MAIN () {
   my $exception-channel = Channel.new;
   for (0..5) -> $partition {

   say "start $partition";

   my $kafka-config = PKafka::Config.new({
   'metadata.broker.list' => 'kafka-dev-1:5551, 
kafka-dev-2:5551, kafka-dev-3:5551',

   'security.protocol' => 'ssl',
   'ssl.ca.location' => '/etc/ssl/ca_server_cert.pem',
   'ssl.certificate.location' => '/etc/ssl/client_cert.pem',
   'ssl.key.location' => '/etc/ssl/client_key.pem',
   'ssl.key.password' => 'password',
   'group.id' => 'metrics-feed-consumer',
   'enable.auto.offset.store' => 'false',
   });
   my $kafka-consumer = PKafka::Consumer.new(
topic => 'monitoring.metrics', brokers => 
'kafka-dev-1:5551, kafka-dev-2:5551, kafka-dev-3:5551',

config => $kafka-config
   );
   $kafka-consumer.messages.tap(-> $msg {
   given $msg {
   when PKafka::Message {
   say "$partition : got {$msg.payload-str}";
   $kafka-consumer.save-offset($msg); # <--- guilty line
   }
   }
   });

   my $worker-done = $kafka-consumer.consume-from-last(partition => 
$partition);


   $exception-channel.send($worker-done);
   }

   react {
   # handle exceptions
   whenever $exception-channel -> $promise {
   whenever $promise {}
   }

   # fininsh up properly with signals
   whenever signal(SIGINT,SIGKILL) { done }
   }
}


 end of code

Could that an MoarVM issue? Could it be some threading issue withing 
librdkafka? Or in the interaction between both?



Cheers
Konrad


--
konrad bucheli
principal systems engineer

open systems ag
raeffelstrasse 29
ch-8045 zurich

t: +41 58 100 10 10
f: +41 58 100 10 11
k...@open.ch

http://www.open.ch



smime.p7s
Description: S/MIME Cryptographic Signature