# New Ticket Created by  "Carl Mäsak" 
# Please include the string:  [perl #64928]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=64928 >


Apologies, the below discussion is long and involved. I've tried to
simplify and reduce as much as I can.

<masak> rakudo: class A { multi method dispatch(@chunks, %param?) {
say %param.perl, defined %param } }; A.new.dispatch([1,2,3]);
A.new.dispatch([1,2,3], { "OH" => "HAI" })
<p6eval> rakudo 69b318: OUTPUT«{}1␤{"OH" => "HAI"}1␤»
<masak> I'm slightly surprised that the former is defined.
<masak> but maybe it has to be that way.
<moritz_> masak: that's because %param is an instance
<masak> an instance?
<moritz_> objects
<jnthn> An instance of Hash
<moritz_> objects of normal classes are always defined
<masak> ok, you two don't seem to think this is an error, so I guess it isn't :)
<frettled> masak: I think I grokked the code in your previous example
now, and yes,  think it makes sense that it works the way it did.
<masak> frettled: with the instantiated hash?
<frettled> masak: yep
<masak> frettled: well, I just want a simple way to test if the
parameter was passed.
<masak> frettled: or maybe {} is the default for Hash...
<frettled> masak: the way I read the spec, the default values are the
ones you specify in the sub declaration.
<moritz_> frettled: if %h were undef, you couldn't assign values to it
<masak> ack. it's more dwimmy that it's {}.
<frettled> moritz_: hrm, that's breaking the principle of least surprise.
<masak> but... I just want a nice way to see if the hash was passed or not.
<moritz_> frettled: maybe the spec needs to be updated to only refer
to scalar optional parameters
<frettled> moritz_: or to allow assignment to undefined non-scalars ;)
<p6eval> rakudo 69b318: OUTPUT«{"a" => 5, "b" => 2, "c" => 3}␤»
<moritz_> frettled: that would be much weirder, overall
<frettled> moritz_: would it?
<moritz_> frettled: yes.
<frettled> moritz_: I don't see how, though.
<moritz_> frettled: if you have an undef value, it's usually not a
"normal" object, but a proto object
<moritz_> frettled: so if a default value is such a proto object, a
%h<a> = 3 would call the postcircumfix:<< < > >> method as a class
method
<moritz_> frettled: which doesn't have access to attributes - so it's
going to barf
<masak> moritz_: what does 'my %h;' do?
<moritz_> masak: it calls Hash.new under the hood, I assume
<masak> then it can be argued that '%h?' should, too.
<frettled> moritz_: so essentially, it's been designed into a corner
where you can't get out of without getting hacks all over your feet ;)
<moritz_> frettled: right
<frettled> moritz_: $expletive
<moritz_> frettled: of course there are other options...
<frettled> moritz_: yes, _is rw_, for instance, seems like it would help.
* frettled is a Perl 6 spec n00b, though.
<moritz_> frettled: like having %h? defaulting to a Hash.new(defined => 0) or so
<frettled> moritz_: no, that's the wrong solution, because it still
means you can't say whether you got passed an empty hash or not.
<moritz_> frettled: you could, because an empty hash defaults to being defined
<frettled> ah, I misunderstood the magic
<moritz_> but there's a drawback... every modifying call to a hash
would have to set its defined flag
<frettled> mm
<frettled> I think this is a design weakness.
<moritz_> the problem is that we're doing in-band communication
<moritz_> instead of asking the hash parameter if it was defined, we
should ask the capture if that hash was given
<masak> aye.
<moritz_> especially since objects can respond with False to .defined
at will anyway
<frettled> the way you put it, it seems like there is a
straight-forward way of doing so, and that would be good.
<frettled> Conceptually, that's much cleaner than asking the variable.
<moritz_> the simplest solution that works with the current spec is to
split it into two multis
<moritz_> but that's not always convenient
<frettled> I was considering to suggest that, but I thought it would
be neater to use the optional argument as, well, optional.
<frettled> In more complex cases it would make more sense to create
multiple methods.
<frettled> (going Java)
<frettled> There doesn't appear to be a test for this in S06, though.
Unless I'm misreading the tests or missing a test, only scalars are
tested.  But my test-fu is weak.
<moritz_> frettled: it might well be missing... but let's try to get
clarification on the spec first, and then write tests :-)
<frettled> moritz_: yep.
<frettled> moritz_: though the spec is pretty clear about it, really,
I just had to read the right part of it.
<frettled> It's right there in the intro of S06/Parameters and arguments/
<frettled> It speaks of "container argument" as opposed to a scalar.
<frettled> so if anyone has the test-fu to write a test for testing
whether optional hash and array parameters are 1) immutable, 2)
defined with their correct default value, and 3) handles correctly
with is rw, is copy, etc.
<frettled> ...that would be nice. Then I can leech on and see how
that's tested.  :D

...meanwhile, a bit later...

<masak> rakudo: class A { has Callable $.c; method foo() { say defined
$.c } }; A.new.foo
<p6eval> rakudo 69b318: OUTPUT«1␤»
<masak> I must say this is highly counterintuitive.
<masak> if that one is defined, what in the world is it defined to be?
<masak> I feel both this case and the case with the default parameters
undermines thewhole concept of definedness.
<masak> to me, 'defined' should be able to show whether the variable
in question has been assigned to, initialized etc.
<masak> moreover...
<masak> rakudo: class A { has $.c; method foo() { say defined $.c } };
A.new.foo[14:28]
<p6eval> rakudo 69b318: OUTPUT«0␤»
<masak> now it works as we all expect it to!
<masak> so the current behaviour is actually a kind of punishment for
adding types!
<baest> masak: I think it's only Roles
<baest> rakudo: class B { }; class A { has B $.c; method foo() { say
defined $.c;} }; A.new.foo;
<p6eval> rakudo 69b318: OUTPUT«0␤»
<masak> baest: I think you're right.
<masak> but I don't think roles should behave like this either.
<baest> indeed
<baest> would be _very_ weird
<masak> moritz_ seemed to argue earlier that the optional-params case
was correct.
<frettled> Yes, at least correct according to spec, and as far as I
could tell, it was.
<masak> right.
<masak> that's why I'm not submitting it as a rakudobug, because it's
really a spec issue.
<frettled> masak: Yes, and I don't think I quite got an answer to how
to check whether an argument was used in any other way than doing
multiple dispatch to eliminate the alternatives.
<masak> frettled: indeed.
<masak> this discussion is not-yet-resolved.
<frettled> Since defined() obviously isn't the correct way to do it,
an alternative method is necessary, e.g. another property for each
parameter that's specified in the sub/method definition.
<frettled> That would be quite useful, since it allows us to separate
between the following cases:
<frettled> 1) The parameter was not used.
<frettled> 2) The parameter was used, but was undefined.
<frettled> I'm not eager to fight for this, since I'm not sure where
the snowball will stop rolling.
<masak> whoa, "obviously isn't the correct way"? please explain -- I
didn't know it was obvious that it isn't the correct way, let alone
that it isn't the correct way...
<masak> frettled: for a typed parameter, the case 2) will never occur.
<frettled> masak: ah, right, that was mentioned earlier as well.
<frettled> I used "obviously" loosely; it's not quite obvious to me
that this is the way it _ought_ to be, but it's obvious that it's the
way it _is_.
<masak> ah. :)
<masak> I think 'defined' should be used to test whether a variable,
parameter or attribute has been initialized.
<masak> I think that typing shouldn't affect this maxim.
<frettled> Yup.
<frettled> As I said before, it breaks with the principle of least
surprise, and it also breaks with the principle of not having special
exceptions for common cases.
<masak> mm.
<masak> I think I'm ready to submit a rakudobug after all.
<masak> but it'll be one helluva rakudobug... :)
* masak submits

Reply via email to