stevan / p5-mop-redux

A(nother) MOP for Perl 5
139 stars 36 forks source link

Add special NIL constant for slots which are not yet initialized #44

Closed stevan closed 11 years ago

stevan commented 11 years ago

this is to allow people to tell the difference between a slot set to undef and a slot that has not yet been populated.

14:11 phaylon: I was just wondering, would there be a way for me to know whether an attribute has a value or not without a trait giving me a method?
14:21 tobyink: phaylon: mop::attribute has a `has_data_in_slot_for` method.
14:21 perigrin: phaylon: mop::util::find_meta($meta)->get_attribute('$attribute')->has_data_in_slot_for($meta, ${^SELF});
14:22 perigrin: sorry s/$meta,//
14:22 tobyink: Also, prefer s/mop::util::find_meta/mop::get_meta/
14:23 tobyink: Oh, and it's mop::util::find_meta($classname) anyway.
14:23 perigrin: I'm just copying from something doy pasted a few days ago
14:23 perigrin: http://paste.tozt.net/2013-07-23xGthHyQ7-test.pl
14:23 perigrin: I do that well :)
14:24 perigrin: tobyink: find_meta can take either a classname or a blessed instance
14:25 perigrin: it passes the first argument to get_stash_for() which does my $class = ref($_[0]) || $_[0];
14:25 tobyink: Yes, mop::util::find_meta should work, but mop::get_meta is the public API. It e.g. throws a sensible error message instead of just returning undef.
14:25 tobyink: perigrin: yes, but the blessed instance is an instance of the class, it's not the metaclass.
14:26 perigrin: mop::get_meta(${^SELF})->get_attribute('$attribute')->has_data_in_slot_for(${^SELF});
14:27 perigrin: phaylon: that's I think the properly pained bikeshed.
14:32 phaylon: well, that's kinda wordy, but alright :)
14:33 phaylon: I don't really have a use for it anyway, it was just a thought :)
14:34 leedo: that seems like something you wouldn't need the mop to find out
14:36 perigrin: leedo: one could hope that "defined $attribute" might work but the instances in p5-mop are intentionally opaque
14:36 perigrin: so exists $self->{attr} doesn't dwim.
14:37 leedo: right, i was just thinking the former would work
14:38 perigrin: leedo: might, but with the current setup in the prototype, I know the mop version will :)
14:38 stevan: defined $attribute will work, inside a method
14:38 stevan: leedo: perigrin: ^
14:38 stevan: outside a method, nope
14:38 stevan: you need the mop
14:38 perigrin nods
14:38 stevan: but if you did exists $myobj->{foo} outside a method, you should be shot
14:38 phaylon: well, one argument against defined($attr) is that if you don't have a type constraint on it, your public api will include undef as no-value
14:38 tobyink: defined $attribute works, but doesn't distinguish between exists and ==undef.
14:38 stevan: phaylon: that is true
14:39 stevan: on both accounts
14:39 perigrin: time to override CORE::exists
14:40 phaylon: not to mention the people who will just do if ($attr) if they expect an object, and then 0, '' & Co will also become non-values
14:40 perigrin hides
14:40 tobyink: It would be awesome if exists($scalar) could be hijacked.
14:40 stevan: it might be able to be
14:40 phaylon: in my toy-thingy I was thinking about a boolean twigil like $? for existance vs $. for access, so you never have to type more to be correct
14:40 stevan: actually, come to think of it
14:41 stevan: the variables are created in the method preamble
14:41 stevan: and like all scalars they are undef
14:41 stevan: so, they are always undef
14:41 tobyink: phaylon: tricky to parse
14:41 stevan: if you explictly want to check defined in storage, that is different
14:41 phaylon: tobyink: in perl, yes :)
14:41 stevan: phaylon: yeah, I have been told twigils are a LOT of work
14:42 stevan really needs to write a Moose->mop manual
14:42 stevan: but right now, I need to shower
14:42 phaylon: well, in perl 5, not to offend someone :)
14:43 phaylon: one usecase I could think of is dumb serialization of data, where I'd currently do e.g. { $self->_has_foo ? (foo => $self->foo) : () }
14:44 stevan: yeah I gotta do some thinking
14:45 stevan: cause, well, I think I caused trouble with Moose
14:45 phaylon: maybe just propose to p5p to introduce a new value: notevenundef
14:45 stevan: which is why people like MooseX::UndefTOlerant
14:45 stevan: phaylon: I think scalars have some weird stuff that makes them init to undef
14:45 stevan: we hit this crap in Package::Stash
14:45 phaylon: ooh, $attr < undef # bam! now everyone hates you!
14:45 stevan: its built into the language
14:46 phaylon: well, I was kinda expecting this to be more of a theoretical problem, in practices you'd probably just use some trait of cpan in the worst case
14:46 phaylon: s/of/off/
14:47 stevan: wait a second, I am stupid
14:47 phaylon: just noticed I started saying "well" a lot again. probably because of the heat
14:48 stevan: so I control the value in the variable
14:48 stevan: it is only undef if there is nothing in the slot cause of this
14:48 stevan: https://github.com/stevan/p5-mop-redux/blob/master/lib/mop/attribute.pm#L82
14:49 stevan: no reason that can't be
14:49 stevan: my $val = ${ $self->storage->{ $instance } || \$mop::NIL };
14:49 stevan: then people could just do
14:49 stevan: if ( $attribute == NIL ) { ... }
14:49 stevan: where NIL is an exported constant from mop.pm
14:51 phaylon: seems a bit unaligned with how undef is handled. maybe if (nil $attr)? can the new keyword stuff do non-function-call inlining to make it quick? I kinda forgot
14:51 stevan: phaylon: maybe
14:51 stevan: but speed is not an issue now
14:51 stevan: for now it could be a sub
14:52 phaylon: stevan: would this also enable an extension to (for example) die if you try to use a nil value? don't see anything speaking against that, but don't know the internals
doy commented 11 years ago

I'm not sure I agree.

<doy> honestly, i think having separate "undef" and "not set" things almost always ends up more confusing than helpful
<doy> there are certain cases where it does matter
<doy> but there's no reason that those certain cases couldn't just store a scalar ref instead
<doy> i don't think exists($attr) is really all that useful of an api
<doy> you almost always just want either if ($attr) or if (defined $attr)
stevan commented 11 years ago
17:21 stevan: doy: actually, thnking about it
17:21 stevan: has should work just like my
17:21 stevan: my $foo;
17:21 stevan: $foo is implictly undef
17:21 doy: right