Setting private attributes during object build

2012-02-01 Thread yary
I wrote my first perl6 over the weekend, needing some help on #perl6.
And now after finishing some lunchtime thoughts I wanted to post here
on my main sticking point.

If one wants to set a private attribute, one must define a submethod
BUILD. If one wants to use any argument in the constructor other than
a public attribute (positional OR named other than an attribute name),
one must define a method new( ... ).

And if one wants to do both, then the initialization code must be
spread between method new ( ... ) and submethod BUILD.

One fix posited on #perl6 was a blessall method that would act like
bless, but also allow setting private attributes. That would be a
solution... but... how about going all the way and allowing bless to
set private attributes? I wasn't looking when the decisions were made
about bless, and I can understand an argument about not letting
private attributes leak out. On the other hand, if it's OK for a new
blessall, why not for bless itself instead?

-y


Re: Setting private attributes during object build

2012-02-01 Thread Jonathan Lang
Why must we use 'submethod BUILD' instead of 'method BUILD'?  Is it some sort 
of chicken-and-egg dilemma?  


Re: Setting private attributes during object build

2012-02-01 Thread Carl Mäsak
Jonathan Lang ():
 Why must we use 'submethod BUILD' instead of 'method BUILD'?  Is it some
 sort of chicken-and-egg dilemma?

Philosophically, BUILD submethods are submethods because they do
infrastructural stuff that is very tied to the internals of the class.
Submethods are internal methods rather than external methods (like
accessors, for example). Submethods don't inherit; each BUILD is
specific to the class it finds itself in and not its deriving classes.
The only sense in which it's akin to a chicken-and-egg dilemma is that
a BUILD submethod assumes that it can access the class's attributes,
but not that it can use accessors and other external methods.

// Carl


Re: Setting private attributes during object build

2012-02-01 Thread yary
On Wed, Feb 1, 2012 at 3:24 PM, Jonathan Lang datawea...@gmail.com wrote:
 Why must we use 'submethod BUILD' instead of 'method BUILD'?
 Is it some sort of chicken-and-egg dilemma?

from S12:
Submethods are for declaring infrastructural methods that shouldn't
be inherited by subclasses, such as initializers ... only the methods
are visible to derived classes via inheritance. A submethod is called
only when a method call is dispatched directly to the current class.

It isn't chicken-and-egg, it's safety. The BUILD submethod doesn't get
used for anything other than the class it is defined in, even if that
class is derived from.

-y


Re: Setting private attributes during object build

2012-02-01 Thread Carl Mäsak
Jonathan Lang (), yary ():
 Why must we use 'submethod BUILD' instead of 'method BUILD'?
 Is it some sort of chicken-and-egg dilemma?

 from S12:
 Submethods are for declaring infrastructural methods that shouldn't
 be inherited by subclasses, such as initializers ... only the methods
 are visible to derived classes via inheritance. A submethod is called
 only when a method call is dispatched directly to the current class.

 It isn't chicken-and-egg, it's safety. The BUILD submethod doesn't get
 used for anything other than the class it is defined in, even if that
 class is derived from.

When I first used submethods, I thought of them as just
subroutine-method hybrids: they are a little like subs because they
don't inherit. They are a little like methods because they take an
invocant. I didn't much care about the infrastructural bit, mostly
using them as a kind of private methods. (Nowadays I use private
methods as private methods.) :-)

Getting back to the topic of the original post: I think blessall is
a bad name for what's proposed, and I don't see a fantastically large
need for that functionality. What's wrong with just defining a BUILD
submethod in the class?

I also don't see a problem of having to divide initialization code
between .new and .BUILD. They have different purposes -- .new is
outwards-facing, receiving arguments. .BUILD is infrastructural and
inwards-facing, building up (as the name suggests) your attributes. If
you need to modify both these behaviors, you override both.

// Carl


Re: Setting private attributes during object build

2012-02-01 Thread yary
On Wed, Feb 1, 2012 at 5:41 PM, Carl Mäsak cma...@gmail.com wrote:
...
Getting back to the topic of the original post: I think blessall is
a bad name for what's proposed, and I don't see a fantastically large
need for that functionality. What's wrong with just defining a BUILD
submethod in the class?

Limiting settable attributes inside new feels arbitrary. It
frustrated me as a beginner. I don't have an opinion on blessall as
a concept or as a name; I do like it as a solution to having to put
object init code in different blocks.

 I also don't see a problem of having to divide initialization code
 between .new and .BUILD. They have different purposes -- .new is
 outwards-facing, receiving arguments. .BUILD is infrastructural and
 inwards-facing, building up (as the name suggests) your attributes. If
 you need to modify both these behaviors, you override both.

 // Carl

new faces outwards but it cannot help but play inwards when it calls
bless. (And if a method new does not call bless, then it isn't a
constructor.)

-y


Re: Setting private attributes during object build

2012-02-01 Thread yary
Looking back at my paltry code, what I ended up doing was having a
BUILD submethod that just listed all my attributes, private and
public, and an empty block, essentially turning bless into
blessall. Which makes submethod BUILD looks like boilerplate, a
magic invocation, repeated in my classes. Not very elegant looking.
Not horrible, just not as good as it could be IMHO.


Re: Setting private attributes during object build

2012-02-01 Thread Moritz Lenz
On 02/01/2012 11:41 PM, Carl Mäsak wrote:
 Getting back to the topic of the original post: I think blessall is
 a bad name for what's proposed, and I don't see a fantastically large
 need for that functionality. What's wrong with just defining a BUILD
 submethod in the class?

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.

Cheers,
Moritz


Re: Setting private attributes during object build

2012-02-01 Thread Damian Conway
Yary wrote:

 If one wants to use any argument in the constructor other than a
 public attribute (positional OR named other than an attribute name),
 one must define a method new( ... ).

Huh? I know I've been out of the loop lately, but this seems fundamentally
wrong.

Constructor args certainly shouldn't be restricted to just the names
of public attributes. And one definitely shouldn't have to redeclare new()
just to allow for more sophisticated initialization. The whole point of having
BUILD() is to separate allocation concerns from initialization concerns.

S12 has an example that explicitly contradicts this constraint that constructor
args have to be public attribute names:

submethod BUILD ($arg) {
$.attr = $arg;
}

Either I'm missing the point here (which is entirely possible ;-) or something
isn't right in the current semantics of object initialization.

Damian


Re: Setting private attributes during object build

2012-02-01 Thread Damian Conway
Moritz clarified:

 In BUILD, the object isn't yet fully constructed, and thus using $.attr
 (which is really a virtual method call in disguise) is wrong. STD and
 niecza already catch that at compile time, and I'm currently trying to
 make rakudo catch it too (branch 'has-self' on github).

Agreed. That example should certainly use $!attr instead.


 More to the point, objects are constructed by .new calling .bless, which
 in turn calls BUILDALL which finally calls BUILD. Since .bless only
 takes named arguments (besides the candidate to be blessed), how could
 BUILDALL know how to call BUILD with positional arguments?

Agreed. That example should be: submethod BUILD( :$arg ) {...}


 Finally Rakudo, Niecza and Pugs all agree that the default .new and thus
 .BUILD only take named arguments, and while that's not authoritative, it
 is a strong indicator that the example above contradicts the compiler
 writer's understanding of object initialization system.

Agreed. I dearly want BUILD to take only named args.


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:

 If one wants to use any argument in the constructor other than a
 public attribute (positional OR named other than an attribute name),
 one must define a method new( ... ).

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. If anything, we should make it
even harder than that. ;-)

But if one can't pass arbitrary named values to the standard new() and
have one (or more!) BUILD methods correctly use them, like so:

class Date {
has Num $!seconds_from_epoch;

multi submethod BUILD (Str :$date) {
$!seconds_from_epoch = _date_from_str($date);
}

multi submethod BUILD (Int :$year, Int :$month, Int :$day) {
$!seconds_from_epoch = _date_from_YMD($year, $month, $day);
}

# etc.
}

and then be able to call:

my $today= Date.new(date = 'Feb 2, 2012');
my $tomorrow = Date.new(year = 2012, month = 2, day = 3);

then we've failed to make Perl 6 even as usable as C++, which is
a tragedy.

I sounds like I simply misunderstood yary's problem, but I'd be
very glad to be reassured that's the case. :-)

Damian


Re: Setting private attributes during object build

2012-02-01 Thread Kris Shannon
On 2 February 2012 17:40, Damian Conway dam...@conway.org wrote:
 I sounds like I simply misunderstood yary's problem, but I'd be
 very glad to be reassured that's the case. :-)

AIUI, yary is talking about the default BUILD submethod that is generated
if you don't provide your own (or maybe its the behaviour of BUILDALL when
it can't find a BUILD submethod) which sets any public attributes from
corresponding named arguments,  but doesn't set private atrributes.


Re: Setting private attributes during object build

2012-02-01 Thread Moritz Lenz
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:

No, the complaint was that when you write self.bless(*, |%named) in your
method 'new', then you have to list each private attribute as

submethod BUILD(:$!a, :$!b, ...) { }

in order for them to be bound to their values.

This is necessary since the change that private attributes cannot be
initialized from the default 'new' constructor, because it's 'bless' (or
the 'BUILDALL' that bless calls) that distinguishes private and public
attributes, not 'new'