This channel is intended for people just starting with the Raku Programming Language ( Logs are available at
Set by lizmat on 8 June 2022.
00:45 Rimnal joined 00:48 Ebudae left 00:58 teatime left 00:59 teatime joined 02:17 teatwo joined 02:20 teatime left 03:57 Rimnal left 04:06 Heptite joined 04:08 Ebudae joined 04:12 Heptite left 04:17 Ebudae left 04:56 deoac left 06:59 kjp left 07:00 CIAvash left, uzl[m] left 07:02 kjp joined 08:41 uzl[m] joined 12:42 CIAvash joined 12:56 habere-et-disper joined
habere-et-disper m: say (1..*).max 12:57
camelia Inf
habere-et-disper m: Int.max
camelia ( no output )
habere-et-disper m: say Int.max
camelia -Inf
habere-et-disper Why is that? Is this another edge case thing? 12:58
Shouldn't `Int.max` be `Inf` too?
moritz m: say Inf ~~ Int 12:59
camelia False
moritz that's the problem 13:00
habere-et-disper Is it trying to say it's undefined ? `Inf` aside, how can it be negative ? 13:07
m: say UInt.max.sign
camelia -1
13:16 Heptite joined 13:37 habere-et-disper left
Nemokosch I'm not sure if this was you but I have seen this mistake before. Int is not a set of values, neither is UInt, for that matter 14:12
14:17 tea3po joined 14:18 tea3po left, tea3po joined
in this context, Int, or UInt, is simply a placeholder value for something missing, hence it's immediately disqualified from the comparison, and you are basically asking the maximum of nothing 14:19
14:20 tea3po left, tea3po joined, teatwo left
so it is indeed "another edge case thing" and probably it would be better if it didn't execute in the first place 14:21
also, it could be a problem that Inf is not an Int but here that doesn't matter; Num.max is also -Inf for the same reason 14:22
I have already mentioned the problems of a mere Num value being used as a type-agnostic wildcard; this is a different thing 14:24
gfldex m: Int.^mro.say; 15:35
camelia ((Int) (Cool) (Any) (Mu))
16:21 deoac joined 16:55 deoac left
librasteve 20:19
your handy FPU has a standard way of doing +/-Inf ... this is the raku way to leverage that 20:20
the idea afaik is that as you get beyond the range of Rats then the efficient way for your machine to handle bigger numbers is Nums so there is graceful degradation of precision, but not of accuracy 20:22
then, if you run out of Nums you get to Inf 20:23
m: say Inf ~~ Real 20:25
Raku eval True
Nemokosch Yes, Inf has a clear meaning in floating point context; however, we have it here in untyped context, conceptually 20:31
so there is this cross-proliferation
the end result is that you can have an array of type X (say, integers) such that the maximum or minimum value is not of type X but a completely arbitrary type (floating point number) 20:34
librasteve raku is brilliant in "untyped" concept ... since it can seamlessly handle ops that combine Int, Rat, Num AND has a type model with proper inheritance so that
m: say Int ~~ Real; say Num ~~ Real; 20:35
Raku eval True True
librasteve for example
m: say Int ~~ Real
Raku eval True
librasteve m: say Num ~~ Real; 20:36
Raku eval True
librasteve and so on
m: (1, 1.1, 1e1).are 20:37
Raku eval
librasteve m: say (1, 1.1, 1e1).are
Raku eval (Real)
Nemokosch okay but this has nothing to say about the sanity of a maximum of an array degrading into a different type 20:38
in before yes, this has caused me actual problems in code
librasteve m: say [+] (); say [+] (2); say [+] (2,3); 20:39
Raku eval 0 2 5
librasteve so, as you have said, the identity operation of + is 0 20:40
m: say [] (); say [] (2); say [*] (2,3);
Raku eval 1 2 6
librasteve and the identity operation of * is 1
m: say [max] (); say [max] (2); say [max] (2,3); 20:41
Raku eval -Inf 2 3
lakmatiol JS also does the maximum of 0 is -Inf thing, and it is pretty much never as ergonomic as a language designer would like it to be
Nemokosch that's because * and + are designed to be operators unambiguous and exclusive to usual math
librasteve so I like that the identity of min/max has the same approach 20:42
Nemokosch which is something that I have advocated for every now and then, i.e "don't ever overload these operators please" because of the broken assumptions
however, minimum and maximum are conceptually overloaded for different types of data 20:43
librasteve huh?
Nemokosch I got curious and I checked this. Is there a general purpose utility for min/max, or just Math.min? 20:44
lakmatiol just the Math.min and Math.max afaik, but they are variadic
Nemokosch for Math.min, I'd say it might actually be sane
In JS "Math" usually implies floating point context 20:45
lakmatiol even among floats, it is an error more often than it is a desirable default
Nemokosch it wouldn't make sense to ask Math.min about the strings, right?
lakmatiol ye, it is less bad in JS
Nemokosch Well I can't see why it wouldn't be a desirable default but perhaps I'll have to take your word for it 20:46
librasteve so imo, raku is saying "if you don't care about types, then you can min/max anything Real in a List, but WATCH IT if your List is empty"
Nemokosch min/max even works (and it is supposed to work!) on strings, and any types with a given cmp ordering 20:47
librasteve you can't ask raku to give you min/max of Strings
Nemokosch you can
you absolutely can
librasteve since it uses a <=> not a cmp and that coerces the Str to its .elems 20:48
lakmatiol m: <a b c b a>.max andthen .say # this is what Nemokosch means
Raku eval c
Nemokosch it doesn't coerce into anything, it uses cmp actually 20:49
lakmatiol julia julia> minimum([]) ERROR: ArgumentError: reducing over an empty collection is not allowed This just seems like objectively superior behaviour to me, especially in raku where you have excellent facilities for dealing for various kinds of failures.
librasteve oh - my bad - thanks for educating me
all the same, I think that raku is not just another julia for this kind of things 20:51
Nemokosch by the way 20:52
yes yes, I know, not beginner-friendly enough
but ultimately it's a common interest to get people into Rakudo anyway, whatever I think about that
librasteve making raku behave like julia is not going to get people into it ;-) 20:53
lakmatiol though to be fair, -Inf does compare less than to most things
m: max ().max, <a b c b a>.max andthen .say 20:54
Raku eval c
librasteve the point is that raku is designed to work very well when you are in untyped mode (as well as in typed)
Nemokosch Comparing -Inf and 'honeybee' makes no sense tho
librasteve why not?
lakmatiol well, the solution I would accept of raku would be a special polymorphic "less than everything else" object
which could very well -Inf
which doesn't sound right
Nemokosch and by "makes no sense", I mean it's actively harmful to get a floating point number from some number of strings
lakmatiol the more interesting issue is how do I do a max with a default 20:55
Nemokosch especially that Raku will then be happy to use -Inf the floating point number through a Stringy interface
lakmatiol raku > ().max // 5 -Inf doesn't work
librasteve m: say ( ().max , "honeybee").max
Raku eval honeybee
librasteve ^^ look no type error ... just works 20:56
Nemokosch so afterwards you will have no way to even tell why you got the string "-Inf", unless you planned for this case a priori
lakmatiol there is no "use the rhs if the lhs is -Inf" operator, since -Inf is not actually a :U
Nemokosch it is DEFINITE, it is defined and I think it is even truthy
m: 20:57
Raku eval True
Nemokosch I don't think you can recover if you did call max on an empty (or empty-ish, only undefined values) Iterable 20:58
lakmatiol you can know to check for -Inf, that's about it
Nemokosch you actually need to implement a saner default every time this comes up as a possible problem
lakmatiol IMO something like a Least:U with the same comparison semantics would be better 20:59
then I can // it, I can't ~ it, etc.
Nemokosch well, there is that issue I opened a while back
librasteve recover from what - it doesn't throw an error when you compose it (see my example) ... maybe I'm missing a concrete example here 21:01
lakmatiol something like perl my @names = ...; my $example = @names.min; say "The first name alphabetically is $example" 21:02
librasteve I think that the raku way to handle anything that is an operation is that in general it will never revert to a type object 21:03
lakmatiol this does not behave usefully with -Inf
Nemokosch something else: 21:04
lakmatiol oh yeah, if you want the type checking, this won't type erorr, huh 21:05
well that's awful
Nemokosch and you know, frankly, one shouldn't need to argue about type sanity
I'm definitely not a static typing freak but it's just damn obvious that a type system is only useful if it's sound 21:06
librasteve raku type checking is often dynamic --- don't see an issue with that in particular 21:07
Nemokosch you should at least see an issue with an array of strings producing a floating point maximum 21:08
lakmatiol ye, it depends on if raku wants to have an optional type system, or something to the clojure spec kinda thing where it's runtime assertions
Nemokosch if you don't see a problem with that, I don't think there is any point in discussing this whole thing
librasteve in the input example you are saying "I will accept any input, then try to coerce the result of an operation to Str" ... which I guess you get the Str "-Inf" if you enter an empty Str
Nemokosch it shouldn't ever hit a floating point value 21:10
librasteve raku is a world where you can have typed or untyped "contexts", when in untyped, I see no issue with mixing types 21:11
otherwise you have Rust
lakmatiol there is no typed variant of min
min is simply always unsound 21:12
librasteve min is an operation
not a variable
lakmatiol functions also have types
Nemokosch like how to put it... having Inf come out of any sort of non-numeric list is equally bad as having 42 come out 21:13
they are both arbitrary values one needs to write further checks for, wherever they happen
and if you don't remember to write those checks, nonsense will come out, implicitly
it's guaranteed to be nonsense by the sheer nature of particular types not having any concept of Infinity, let alone a numeric one 21:14
librasteve I am not sure that raku maintains a concept of sound operations where the type of the result is aligned to the type of the argument 21:15
lakmatiol that's a bad thing if you want a useful type system though
if you see the the type specification system as a way to do runtime assertions on types which can occasionally figure out an error at compile time, it is fine 21:16
librasteve yes and no - it would be a killer with strong / static typing, I agree
so raku "gradual" typing is not everyone's cup of tea since a lot is left to runtime
Nemokosch this is not just about the type system being static
librasteve but I for one much, much prefer it to eg Rust 21:17
lakmatiol gradual typing generally implies that the parts you do type are typed soundly.
Nemokosch types themselves are an abstraction
lakmatiol which is just... not true in raku
but it works fine in e.g. python
librasteve well, so yes there is a interface between untyped and typed worlds
Nemokosch if you have a list that you initialize a certain way, you can semantically describe the type of your data, that's how you can think of dynamically typed stuff as well 21:18
librasteve and in raku this is gated with runtime assertions
lakmatiol well, yes, that's what I said, if you want to be in a typed world, you can never use min or max
Nemokosch now if you can semantically expect your list to contain a certain number of strings, and then you cannot expect the minimum of them to either be a string, or at least warn about a special case going on, that's definitely a problem 21:19
whether you use type annotations or not
I for example did not, yet it was a problem, because of the useless semantics of the outcome
a type error is really not the worst thing that can happen 21:20
having a nonsensical string come out 10 operations later, is way worse
so granted, this sort of soundness is strictly necessary for proper static typing - but it is also universally beneficial without 21:21
librasteve would you outlaw doing min/max unless all types in list the same? 21:22
lakmatiol if you are writing type hinted code, you will likely have that property upheld anyway, so sure 21:23
Nemokosch let's say the tradeoff explicitly
the behavior that shoves numeric Inf values onto every use case is beneficial for the use cases where you do indeed mean to compare numbers, and floating point numbers in particular 21:24
librasteve m: my @names = []; my Str $example = @names.min;
Raku eval Exit code: 1 Type check failed in assignment to $example; expected Str but got Num (Inf) in block <unit> at main.raku line 1
lakmatiol it is useful for any case where you want to do further comparisons on the result, to be fair 21:25
Nemokosch it saves you, say, one condition
one condition that you would know about rather clearly, though
librasteve ok, so we agree that min/max in untyped context should be able to handle a mixed List - phew! 21:26
lakmatiol honestly, the example for static typing may as well just be my Int $i = <a b c>.max, which also crashes at runtime
Nemokosch on the other hand, it is detrimental in any other cases, in a way that you need to explicitly learn that although ().min/max does give you a value, it will be a useless value that you need to guard against
lakmatiol I did kind of forget that the raku type checking is more cosmetic than useful. 21:27
Nemokosch if min/max was strictly about numeric comparison, Inf - preferably as an abstract Real value, not a Num - could do well 21:28
librasteve so, then the question is should min/max be able to mix numbers and strings given it uses cmp semantics, which boils down to should cmp be able to take a number and a string
lakmatiol that's not quite the discussion
Nemokosch well, that could also be a discussion 😉 21:29
there are many things to get wrong here, to be honest
have you heard of IntStr?
lakmatiol the question is: should a function introduce a whole separate type of value which at no point anyone actually cared about or even instantiated? 21:30
librasteve m: my Str @as="a","b"; my Int $a = @as.max; say $a;
Raku eval Exit code: 1 Type check failed in assignment to $a; expected Int but got Str ("b") in block <unit> at main.raku line 1
lakmatiol when it's a:U, it's a thing that raku has tools for dealing things, same with a failure of sorts. But a plain ol' float requires a special check entirely 21:31
Nemokosch I'm not sure that's really the question
or maybe I just don't get you, lol 21:32
lakmatiol honestly, I am just not a fan of sentinel values
should've kept that mess in C where it belongs
would this pass code review? perl my $el = @xs.max fail "no elements" if $el ~~ Num 21:33
Nemokosch lmao
librasteve well lets backtrack from Least:U ... your suggestion .... I have said that this concept should be defined ... so I don't think it is unreasonable in an untyped context to pick up -Inf since that is definitively a standard way to say "the most negative thing this machine can represent"
Nemokosch no, because you forgot the semicolon!
lakmatiol truee 21:34
librasteve lol
I always forget the say
Nemokosch I think even this phrasing is presumptuous - a string is not positive or negative 21:35
neither is business logic object of any sort
+ a
lakmatiol the smallest thing being -Inf is... cute, in the same way pony not having operator precedence is cute 21:36
librasteve look, I would support some defined "lowest possible Str / highest possible Str" when doing a leg
Nemokosch not having operator precedence is not just cute but also simple
librasteve as a new raku build in class 21:37
Nemokosch something not to neglect
librasteve yeah - but if we are in Real children territory it can fully participate in subsequent math and do a sensible thing 21:39
m: say Inf + 1
Raku eval Inf
lakmatiol min is not a numeric operator though 21:40
it works on anything you can compare, and so it should behave like it.
and while -Inf does indeed behave like the smallest thing, it also behaves like a lot of other things, only some of which make sense in a given context 21:41
librasteve well I am basing on cmp being [<=>|leg] and that if all are Str then leg would apply
but this idea of LowestPossibleString is also bad because you can't just use 'A' if you want to follow the identity pattern 21:42
Nemokosch whether we like sentinel values or not, there are clear differences 21:45
what purpose they are defined for, or how easy it is to mistake them for valid values 21:46
librasteve maybe '' (empty Str) is a good candidate for LowestPossibleStr
but I can't fathom what to do for HighestPossibleStr 21:47
Nemokosch although I also don't vehemently oppose the idea that "the smallest something in the universe" just shouldn't be a valid query, and hence should throw some way
librasteve so - I dare to say that we both think that raku should warn if you min/max an empty List 21:48
but that no one has a better idea than +/-Inf when it comes to the return value even of a Str array 21:49
Nemokosch I think even dedicated "universal maximum/minimum" values could be better, or Nil, or Empty, or some sort of Failure 21:50
librasteve OK - how about "no change to numbers, but if all .are ~~ Str then return Nil from ().min and ().max and warn 'taking the min/max of an Empty List' 21:52
" 21:53
Nemokosch how do you know about an empty list how it came to be?
I mean, as the core language API
librasteve oh rats - getting late 21:54
that's why I not a language designer! 21:55
must go ... 21:56
Nemokosch and that's why I gave up on trying to bring certain design issues into attention