On Tue Apr 21 06:35:05 2009, masak wrote: > 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
<pmichaud> I've been thinking that "my %h" initializes %h to be the Hash type object <pmichaud> (thinking recently, at least) <pmichaud> with a WHENCE property that vivifies %h into a true Hash when it's used <masak> ooh <pmichaud> same for %h? as a parameter <masak> \o/ <pmichaud> would that solve the problems identified in the ticket? <masak> oh yes, oh yes <pmichaud> (I'm having trouble following the issues there) * masak dances * masak adds this new development to ticket