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
|