On 02/02/2012 07:40 AM, Damian Conway wrote:
> My point was that I don't want the named arguments that BUILD can take
> to be restricted to only the names of public attributes...which was, I
> thought, yary's complaint when writing...

Actually, that *was* one of my complaints, but I was mistaken on that point.

~/rakudo $ perl6
> class A{has $.b; has $!c; submethod BUILD(:$b,:$c,:$x){say "b=$b c=$c x=$x"}}
> A.new(b=>4,c=>5,x=>6)
b=4 c=5 x=6


>If the complaint is that yary wanted to pass positional args to a
>constructor, then I have no problem with having to write one's own
>non-standard new() method to achieve that.

Agreed on that too.

You could break my post down into a few distinct complaints. Moritz
distilled the one that matters the most to me, and I'll quote his
first post in full-

>The current approach is violating the DRY principle. When you write a
>.new method that wants to initialize private attributes, you have to
>repeat all their names again in the signature of your BUILD submethod:
>
>class A {
>   has ($!x, $!y, $!z);
>   method new($x, $y, $z) { self.bless(*, :$x, :$y, :$z) }
>   submethod BUILD(:$!x, :$!y, :$!z) { } # is this repetition really needed?
>}
>
>It also means that private attributes are less convenient to work with
>than those with accessors, which IMHO is a not signal in the right
>direction.

And then Moritz expands on that a bit in a later post.


Damian:
>The whole point of having BUILD() is to separate allocation
> concerns from initialization concerns.

Here's where I am late to the conversation, I hadn't known that
distinction. S12 doesn't talk about the "why" of BUILD/BUILDALL, at
least not that detail. If "BUILD" is for allocation, and "new" is for
initialization, then hiding private attributes from "bless" is forcing
the programmer to use BUILD for initialization which wasn't the
intent.

S12 says this about BUILD: "Whether you write your own BUILD or not,
at the end of the BUILD, any default attribute values are implicitly
copied into any attributes that haven't otherwise been initialized.
Note that the default BUILD will only initialize public attributes;
..."

And that's good, because otherwise your private attributes would not
be totally hidden.

"you must write your own BUILD (as above) in order to present private
attributes as part of your initialization API."

And that's not so good, because it forces BUILD to be used for
initialization, and precludes initializing private attributes anywhere
else, like a "bless" called from the "new" method.

I don't propose having "blessall"/new "bless" set attributes directly,
it will still have to call BUILDALL, so derived classes will still
work properly. If we change "bless" to present private attributes to
BUILDALL, then the filtering out of private attributes would move to
the default "new" instead.

For example, to be clear, what we have now:

> class plain{has $.b; has $!c; method say{say "b=$!b 
> c=$!c"}};plain.new(b=>4,c=>5).say
use of uninitialized value of type Any in string context
b=4 c=

> class cust{has $.b; has $!c; method 
> new(:$b,:$c){self.bless(*,b=>$b,c=>$c)};method say{say "b=$!b c=$!c"}}; 
> cust.new(b=>4,c=>5).say
use of uninitialized value of type Any in string context
b=4 c=

What I'd like to see:

> class plain{has $.b; has $!c; method say{say "b=$!b 
> c=$!c"}};plain.new(b=>4,c=>5).say
use of uninitialized value of type Any in string context
b=4 c=

> class cust{has $.b; has $!c; method 
> new(:$b,:$c){self.bless(*,b=>$b,c=>$c)};method say{say "b=$!b c=$!c"}}; 
> cust.new(b=>4,c=>5).say
b=4 c=5

-y

Reply via email to