Re: Missing NullPointerException
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
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
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
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
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
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
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
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