This channel is intended for people just starting with the Raku Programming Language (raku.org). Logs are available at irclogs.raku.org/raku-beginner/live.html
Set by lizmat on 8 June 2022.
scullucs I'm seeing it in the last example of the section docs.raku.org/language/objects#Obj...nstruction 00:05
MasterDuke it's the `Str` type's internal storage of the bytes that actually make up the string 00:10
github.com/rakudo/rakudo/blob/main...akumod#L20
scullucs Ah, I see. Thanks. 00:15
MasterDuke np 00:18
00:39 Tirifto_ joined 00:40 camelia left, Tirifto left, thowe left 00:45 thowe joined 00:54 camelia joined 03:01 hythm joined 05:49 hythm left 07:07 samebchase2 joined, samebchase left, samebchase2 is now known as samebchase 07:15 raf joined 07:16 raf left 07:17 rakuraf joined, rakuraf left 07:20 rakuraf joined 07:43 rakuraf left 08:53 dakkar joined
DarthGandalf Hi, here's the code: dpaste.com/3Y2CLMNVQ G and chk both seem pure to me, but when I add race or hyper to the for loop in part1(), the results become random. I tried to fix it by `$line is copy` in that for loop, but without success. What's wrong? 09:09
this is advent of code 2016, day 4 if anyone wants to try to run that code with an input 09:17
nemokosch Well, do you not want to keep the order of the lines in @nums? 09:44
Fun fact: in order to obtain %c in check by using $name.comb.Bag 09:55
gfldex DarthGandalf: Your code works for me. What does `raku --version` say? 10:00
Nahita it works without errors but doesn't give the correct result i can replicate in 2023.09 10:05
nemokosch If i read the code just one line further... race shouldn't make a difference 10:06
Still, first I'd check it with .hyper.map 10:07
DarthGandalf 2023.10 10:45
from gentoo
v6.d
both hyper and race for me show unstable results run to run; but summing them should make the order irrelevant anyway; the answer is correct if I replace race with 'do' 10:47
lizmat DarthGandalf: my Int %c = Map.new; is basically a no-op, the same as: my Int %c
you probably want something like: 10:48
DarthGandalf nemokosch: interesting, I'll check out Bag 10:49
lizmat my %c := $name.comb.Bag;
ah, what nemokosch said :-)
DarthGandalf I've tried replacing for loop with .map, with same results: $input.lines.map works correctly, but .lines.hyper.map shows random incorrect result 10:53
at least it does it much faster than without hyper :) 10:54
lizmat DarthGandalf: perl6advent.wordpress.com/2016/12/04/ ??? 11:08
Nahita adventofcode.com/2016/day/4 11:09
nemokosch 😂 11:13
I tried to find out if grammar parsing is thread safe, couldn't find anything on that 11:14
I mean it sounds like a huge pain point if it isn't
but interface-wise it does look like a singleton, that much is for sure
lizmat there's nothing really special about grammar parsing: if there is a race condition, it will probably live deep in the NQP regex bowels 11:15
nemokosch okay, so in theory, there shouldn't be a race condition there, right? not if you don't rely on the value of $/
lizmat $/ is lexically scoped 11:16
nemokosch $/ is officially not thread safe but that's besides the point 11:17
if one doesn't use $/, it shouldn't matter
lizmat yeah, but that's the clinch then, as grammars *do* use $/ internally
11:18 CIAvash joined
lizmat also: I still have't found the input file for that advent code post ? 11:18
nemokosch adventofcode.com/2016/day/4/input 11:19
DarthGandalf you need to be logged in, e.g. via github or reddit to download the input for your user 11:21
nemokosch should i upload it with gist? 11:22
lizmat yeah, that'd be easier to check
DarthGandalf ...and I've just remembered that I have it at github.com/DarthGandalf/advent-of-...6/day4.txt 11:23
nemokosch gist.github.com/2colours/b1e3665d7...d51cf16f86
dang lol
lizmat ok, confirmed the varying results 11:26
nemokosch it takes some data to trigger this 11:27
I took the first 20 lines and the result was the same
same for the first 50 lines
for 100 lines it triggered and the value with hyper isn't even deterministic 11:29
🙃
3 runs, 3 different values 11:30
indeed, this is $/ (again... who thought this was okay)
docs.raku.org/syntax/$$SOLIDUS#Thr...ety_issues 11:31
and the workaround works for me: add my $/ in the scope of the block
lizmat ok, it looks like we need a lock on the G.parse :-(
$input.lines.race.map(-> $line {
my $room := $lock.protect: { G.parse($line) }
makes the .race case work reliably 11:32
nemokosch now that I added my $/ in the hyper version, it seems to get it right consistently
lizmat where did you add that ?
nemokosch in the block of the for
so caller side
lizmat interesting... 11:33
nemokosch does somehow .parse just give the value back via $/, even if it is assigned to a variable?
DarthGandalf shouldn't .parse() itself define its own $/ ?
nemokosch anyway, lunch time 11:34
lizmat .parse explictely gets the $/ from the callers context: nqp::getlexcaller('$/')
dakkar Grammar::parse should probably document this gotcha 11:35
DarthGandalf uh, yeah, if I add `my $/;` to the top of the block just before call to .parse, it works fine
lizmat dakkar: I think it's a bug :-) 11:37
running with MVM_SPESH_DISABLE=1 appears to produce the correct result more often
dakkar really? should `$/` always be lexical and not global?
(I mean, yes, I agree it should, I was not aware it was already supposed to be so…) 11:38
lizmat yes
m: $/ = 42; sub a() { say $/ }; a
camelia Nil
dakkar nice! (less nice that the implementation hasn't fully understood that…)
lizmat I think it's some kind of optimization that is play tricks here 11:39
*playing 11:40
11:44 CIAvash left
DarthGandalf erm, another question: I got this: "MoarVM panic: Internal error: Unwound entire stack and missed handler", should I report it somewhere? 11:47
this is me simply trying to add `race` keyword before `for` in part2 at github.com/DarthGandalf/advent-of-...akumod#L29 just to see what happens 11:48
nemokosch it would be good to have an issue for this over-globalization of $/ 11:50
DarthGandalf: from what I understand, a "naive" Raku user should never get MoarVM panic so it automatically qualifies as an issue
DarthGandalf thanks 11:52
nemokosch even if there is a non-recoverable issue, it shouldn't just leak from the runtime 11:53
lizmat So I think this is at the heart of the issue: 11:59
m: 'sub a { dd MY::.keys }; a
camelia ===SORRY!=== Error while compiling <tmp>
Unable to parse expression in single quotes; couldn't find final "'" (corresponding starter was at line 1)
at <tmp>:1
------> 'sub a { dd MY::.keys }; a⏏<EOL>
expecting any of:
lizmat m: 'sub a { dd MY::.keys }; a
camelia ===SORRY!=== Error while compiling <tmp>
Unable to parse expression in single quotes; couldn't find final "'" (corresponding starter was at line 1)
at <tmp>:1
------> 'sub a { dd MY::.keys }; a⏏<EOL>
expecting any of:
lizmat m: sub a { dd MY::.keys }; a
camelia ("\$_", "\$!", "\$¢", "\$/").Seq
lizmat m: -> { dd MY::.keys }()
camelia ("\$_",).Seq
lizmat so, it looks like bare code blocks do *not* get their own $/ created
so they refer to their outer $/, which is then not thread-safe 12:00
nemokosch it would be great if Grammar.parse just outright didn't do the magic via a shared variable
after all, one can go years and years without ever using $/ and it's good practice if anything 12:01
lizmat yeah, agree... but alas, that would break roast and probably at least some ecosystem modules maken 12:02
*maken
nemokosch made? 😛 12:06
rcmlz has been typing for 15 minutes at least... 👀
lizmat no, it just slipped when typing *and* talking to someone here :-)
a race condition in my brain :-)
rcmlz preparing a well formed question - takes time ;-)
Hello, I am doing a simple "max-subarray-sum" exercise and I am wondering if there is a way to make the Raku solution work for "Big" problem sizes - I run out of memory as my current solution reads in the entire input - which is actually not needed for single-pass O(n) solution. method max-subarray-sum(IO::Handle $IN){ my int $max; my int $new-max; my $n = $IN.get; # first line of input contains 12:17
number of integers in second line for $IN.get.split(' ') -> Int(Str) $num { # second line contains list of integers separated by space $new-max += $num; $new-max = 0 if $new-max < 0; $max = $new-max if $max < $new-max; } return $max } Using $IN.getc() gives me the next character, but I would need "all characters until next space" or something similar. Is there an easy way to
read "next integer" from $IN?
lizmat fwiw, on the IRC end this becomes 3 lines of gobbledygook 12:23
nemokosch it doesn't look that terrible; I'd say it's generally too long 12:24
the question is simply how you read characters until the next space, or how you do a scanf("%d") kind of thing 12:25
lakmatiol Why is .words not at all lazy?
nemokosch rather than reading a potentially very long line at once
lizmat .words *is* lazy
lakmatiol At least from my testing on stdin, it very much is not 12:26
lizmat so you're doing $*IN.words or just words() ? 12:27
lakmatiol tried both, neither is lazy
lizmat how did you determine it's not lazy ?
lakmatiol sh $ sh -c 'echo "one two"; sleep 2; echo "three four"' | rakudo -e "say words[0]; \$*IN.flush" one $ sh -c 'echo "one two"; sleep 2; echo "three four"' | rakudo -e "say \$*IN.words[0]; \$*IN.flush" one these only print after two seconds. I would expect them to print immediately 12:30
nemokosch hm, this is kind of a different laziness though, isn't it
it's not about whether the whole line is read 12:31
it's about when the processing of the input stream starts
lakmatiol well, I can't imagine how it would manage to read only part of the input stream, once the input stream closes, without buffering the entire input stream. 12:32
nemokosch I can't imagine either but regardless I think this is generally a different topic
lizmat feels more like a shell issue? 12:33
isn't it that rakudo isn't started until after echo "three four" is executed ? 12:34
if not, it's a buffering issue
lakmatiol $ sh -c 'echo "one two"; sleep 2; echo "three four"' | tcc -run <(echo '#include <stdio.h>'; echo 'int main(){char x[100];scanf("%s", &x);printf("%s\n", x);}') one this prints right away
nemokosch it's not just the shell for sure, cut can fetch the first value right away 12:35
sh -c 'echo "one two"; sleep 2; echo "three four"' | cut -d' ' -f1
yields "one" immediately and "three" after 2 seconds
lizmat in any case, re the race condition with parsing
I have a fix, but it breaks some tests in roast 12:36
nemokosch which tests?
lizmat specifically: { G.parse("foo"); say $/ }
nemokosch Meh, feels like this shouldn't break
lizmat will not show the result of the parse, because the implicit block does not have an explicit $/
nemokosch $/ should be assigned to the outcome of G.parse("foo") 12:37
it should be like a copy
lizmat the $/ above is the $/ of the caller scope
nemokosch rather than the "master value"
lizmat the alternative is to always define a $/ in any scope
which has performance implications 12:38
nemokosch re the implicit block doesn't have an explicit $/ - why is that a problem? can't it be just taken lexically from the surrounding scopes?
the way closures can work and the inner scopes can write lexical variables from outer scopes 12:39
lizmat yes, it does, and *that*s what causing the race condition in the advent code
nemokosch why would it, though, if $/ is just a copy?
and G.parse is backed by a separate local variable, which it should?
lizmat the problem is that G.parse tries to assign $/ in the scope it is called
and if that scope doesn't have it's own, it starts looking up the stack for a $/ and uses that 12:40
*its
nemokosch why does it affect code that doesn't reference $/ on the user side?
like the case here
lizmat and *that* is causing the race condition with .lines.race.map: { G.parse }
nemokosch like okay, I get it, $/ can have inconsistent values. But it is never accessed 12:41
lizmat the $/ is shared by all the worker threads doing the G.parse
it is!
nemokosch but it should be never read?
parsing shouldn't be backed by a shared variable at all
$/ should be only for user interface, never read internally
lizmat hmmmm... 12:42
nemokosch thinking of the C++ principle of "don't pay for something that you don't use"
don't get thread-safety punishment for a variable that you don't even use
lizmat well, that's the idea of not creating a $/ for every scope :-) 12:43
nemokosch imagine that sum or whatever data wrangler function used a shared variable internally, for producing return values... 12:44
suddenly, all those pure functions would have race conditions
lizmat sum takes an iterator, by that time the "race" is already serialized
nemokosch for me, the way I understand Grammar.parse and matching in general, it does just that: it injects race conditions for a variable that should be only an output 12:45
ab5tract would it make grammars any faster if we were to change this behavior? 12:46
something to consider...
lizmat I don't think it would be measurable
nemokosch that's only good. I don't think of this as a performance boost but like sanitizing, so unless it's much slower, it's automatically worth it 12:48
lizmat what I think we *could* do in 6.e with RakuAST to add a lexical $/ if $/ is referred to in that scope, either directly or indirectly with $<foo>
nemokosch there is no reason { G.parse("foo"); say $/ } should break but there is also no reason G.parse("foo") should be thread-unsafe
lizmat and to *not* assign $/ if it is not in the immediate caller's lexical scope 12:49
ab5tract lizmat: that sounds reasonable
lizmat G.parse is only thread unsafe in a block, not in a subroutine / method
nemokosch I meant under any circumstances 12:50
like sum or rotor or whatever
lizmat $input.lines.race.map(sub ($line) {
would also work *ow*
*now
nemokosch if $/ wasn't used internally, rather than a local variable of the method, this wouldn't be a problem I think 12:51
lizmat well, it's use is usually hidden: $0 e.g. is really $/[0]
nemokosch there would be a local variable and right at the end, there would be a lookup to $/ and assigning the local variable to it
lizmat $<foo> is really $/<foo>
nemokosch I know
lizmat nemokosch: I have a patch that exactly does that 12:52
and it doesn/t fix the issue
nemokosch how come?
$/ = $calculated-result doesn't work? 12:53
$calculated-result being the local volatile variable that the method returns
lakmatiol As a weird workaround, if you have excetly one space between all chars, you can use perl $IN.nl-in = ' '; for $IN.lines { .say; } which will not read the entire line at once.
lizmat hmmmm 12:54
nemokosch this is what I have in mind. $/ would only ever appear once in the matching/parsing: at the end, to provide an interface to the user. It would be an "output variable" 12:55
everything else would be done with local variables
lizmat the thing is, that the advent example would be fixed
but any code that would do $0 or $<foo> inside the block, would still suffer from the race condition 12:56
nemokosch yes, you are absolutely right
but that would be a "fair" race condition, if you know what I mean
the user is actually - willingly, if you will - using a shared variable 12:57
lizmat yeah, tell that to the user who thinks that every scope has its own $/ 12:58
nemokosch I think it's easy to explain someone who uses $0 or $<foo> in a situation like that "hey, you are using a nonlocal variable, you should localize it or you get a race condition"
however, it's pretty darn hard to rationalize having a race condition with $/ when you aren't using $/ to begin with
nothing feels right about that workaround I did 12:59
lakmatiol Well, those users do not understand how $/ works, and thus have written buggy code.
nemokosch declaring a variable that nobody used magically fixed the values
lakmatiol If I write something like perl sub f($result is rw); my $out; parallel({f($out); $out.say}); I would indeed expect a race condition. 13:00
nemokosch yes
I'd say there is a difference between "I'm using $/ without knowing how it's scoped" and "I'm using Grammar.parse without knowing that it uses $/ internally and therefore I might need to declare it by hand" 13:01
the latter feels like a very clumsy interface 13:02
remember $[ and $] stuff in Perl? 13:04
lizmat how about in 6.e G.parse would *not* set $/ at all ?
nemokosch the latter feels just like that
"action at a distance"
rcmlz Thank you - that worked for the small test cases, will try now with the big ones. 13:05
nemokosch re not setting $/ at all for 6.e: I'm fine with that; it just doesn't feel necessary. The important thing is that it's not read internally. It could still be set if somebody likes the interface.
lizmat yup, by doing $/ := G.parse 13:06
yup, by doing $/ = G.parse
nemokosch the difference would be ideally one single variable assignment around the end
yes
whether it's the user who does that explicitly, or the implementation 13:07
but all the other parts of the implementation could be the same with either approach
just a wild idea but the whole availability of $/ could even be tied to a pragma 13:08
use result-vars or something 13:09
lizmat DarthGandalf: github.com/rakudo/rakudo/commit/8542ad2116 13:40
DarthGandalf yay, thanks 13:46
I'll report my other bug properly later today when I get home 13:47
nemokosch thankies 13:49
antononcube @DarthGandalf Great handle! Cannot help suggesting the variation "GanthDarfal". 14:42
lizmat and yet another Rakudo Weekly News hits the Net: rakudoweekly.blog/2023/11/27/2023-...-ab5tract/ 16:47
17:35 dakkar left
librasteve from a point of great ignorance, I would be very (pleasantly) suprised if Grammars could be made thread safe, but I am sceptical ... knowing that even a simple Array object is not thread safe, then I would say that the Match object (as some kind of "uber Array") is also not thread safe. And a sophisticated Grammar / Action set will very commonly have code in it like this: 18:08
#| accumulates element Units using times method compound($/) { my $acc = Unit.new; for $<element>>>.made -> $x { $acc.times($x); } make $acc; }
where make and made are heavily accessing the same Match object in an unpredictable "event driven" sequence depending on the subject text 18:09
you can't keep all that to the end! 18:10
(maybe I am missing something - happy to be proven wrong) 18:11
nemokosch don't forget that parsing different (unrelated) content, the Match objects aren't even meant to be shared 18:20
no content is meant to be shared across threads in the parsing; each individual parsing task is solely in its own one thread 18:21
this was the use case here
librasteve oh ok - then I guess that could work ... thanks for the clarification! 18:22
nemokosch 🍬 18:26
lakmatiol Did some more digging on the whole is .words lazy thing, turns out it is indeed lazy, just needs $*DEFAULT-READ-ELEMS bytes to start outputting things (so it would be fine for @rcmlz usecase, that's mb) $ yes | python -c 'for i, l in enumerate(open(0)):print(format(i, "9"), end="\r", flush=True, file=open("/dev/tty","w"));print(l,end="")' | rakudo -e 'say words[0]' y 32792 broken pipe 21:03
DarthGandalf github.com/rakudo/rakudo/issues/5478 has minimal example of my other bug 21:16
23:59 lizmat_ joined