On Sat, Jun 14, 2008 at 01:46:10PM +0200, Moritz Lenz wrote:
: In the test suite and on IRC there was quite some confusion about how
: list builtins are specced, and how they should behave in corner cases.
: 
: One is join():
: our Str multi method join ( @values: Str $separator = ' ' )
: our Str multi join ( Str $separator = ' ', [EMAIL PROTECTED] )
: 
: It is quite clear that the perl 5-style
:    join 'sep', $value, $value2;
: invocation remains valid, and
:   @list.join($sep)
: is the new method form.
: 
: The confusion arises what to do with
:    'str'.join('other_str')
: should be.
: 
: Fallback semantics in S12 suggest that since no matching multi method is
: found, subs are tried - that is, the expression is interpreted as
:    join('str', 'other_str')
: yielding 'other_str'. t/spec/S29-list/join.t disagrees, and wants the
: result to be 'str'.

I want the result to be 'str'.

: Daniel Ruoso argued in favour of the tested behaviour, suggesting that
: perhaps the specs should be updated accordingly, mostly because
:    ('str').join('other_str')
: would be confusing otherwise.

More to the point,

    $unknown.join('other_str')

needs to work well, I think.  And that means even if $unknown doesn't
know whether it's singular or plural.

: Patrick Michaud argued in favour of the specced behaviour, and I agree.
: Mostly because nobody sane will write things like
: 'str'.join('other_str') with a literal string as the invocant in first
: place. And if it's not a literal, and you want it to behave as list, the
: invocant is either something that returns a list, or a variable with the
: '@' sigil. We just need to be careful that everything that should return
: really does that, even if it contains a single list.

Patrick and I discussed it on the phone the other day and came to an
understanding, I think.

: Currently both pugs and rakudo make <a b> return a list (pugs actually
: an array, but that's a different problem), but <a> is a Str.
: If we'd just be more consistent and always return a list, I don't see a
: problem with the spec. If not, it would be rather weird to have <a
: b>.join('c') return 'abc', but <a>.join('c') return 'c'.

<a>.join('c') should return 'a'.

: Consider
: my $x = A.new();
: $x.y = <a>;
: say $x.y.join('b')
: The output is different for the two possible declarations of class A:
: class A { has $y is rw } # -> b
: class A { has @y is rw } # -> a
: not pretty IMHO.

Indeed.

: So I see the following options:
:  1) be more consistent with what returns a list
:  2) Add a method with invocant Any for each list builtin
:  3) drop method fallback, thus disallowing Str.join(Str) outright
:  4) be lisp, make everything a list *g* (not serious)
: 
: I haven't thought a lot about the third option, and what it would mean
: to the language as a whole, so I have no idea if it's a viable alternative.

I have been advocating for 2, and am considering doing 3 as well.
There's more than one way to do 2--we could, for instance, have some
magical syntax for saying that a class's invocant may be converted
from Any.  But what Patrick and I decided on Wednesday was that, for
now, we'd go with the simplest approach, which is not to invent any new
syntax or semantics, but simply have the Prelude install Any methods
as defaults for universal methods such as .join that want to convert
the invocant to a particular type across the language as a whole.
No fallback is then necessary, and the fact that the Prelude is
defining language-wide default semantics is not a problem at all,
because that's precisely what the Prelude is for.  And I don't see
any problem with the Any class claiming to own .join since subclasses
can still override if the like.

Larry

Reply via email to