Re: Custom object constructors
Kevan Benson wrote: > That said, I submit that it's a very confusing part of the language as > defined currently, and I haven't seen a very thorough explanation of the > purpose of each method in the chain the instantiates a new object. S12 > touches upon them slightly, but not in enough detail that I was able to > work out where I should be adding code to appropriately make alternate > constructors. I've tried to explain that here: http://perlgeek.de/blog-en/perl-6/object-construction-and-initialization.html (If anybody thinks part of this is worthy backporting to the specs, feel free). Cheers, Moritz
Re: Custom object constructors
Jan Ingvoldstad wrote: On Thu, Aug 20, 2009 at 10:44 PM, Kevan Benson wrote: That said, I submit that it's a very confusing part of the language as defined currently, and I haven't seen a very thorough explanation of the purpose of each method in the chain the instantiates a new object. S12 touches upon them slightly, but not in enough detail that I was able to work out where I should be adding code to appropriately make alternate constructors. Now that you apparently understand it, do you have a suggestion on how S12 might be phrased differently? I must admit that I don't quite grasp the concepts here yet, so an alternate wording might help others as well. Thanks for bringing the question up. Unfortunately I'm not at all confident I do understand it all, but I'll explain how I think it works and people more knowledgeable than me will hopefully step in and explain where I'm wrong. Maybe out of this we can get some consensus on what needs to be added WRT object constructors in S12. The creation sequence looks something like this: .new(args) { my $self = .bless(class, { .BUILDALL(class, args) { # in reverse MRO for (@parent) { .BUILD(class, args) } .BUILD(class, args) } } Note: Actually, I believe the current .BUILD is actually called as part of the call to all parent .BUILD methods in Rakudo. At least that's what I'm able to infer from the parrot code for Rakudo objects at src/classes/Object.pir starting at line 272 (thanks japhb!). .new - Handles the actual call to .new from code, define other submethods/methods for this if you want to create alternate constructors. You should normalize all paramaters to named values before calling .bless. S12 implies that any .new you write (or a constructor of any other name you define) must call .bless. .bless - See S12 (http://perlcabal.org/syn/S12.html#Construction_and_Initialization) for more info, but this is responsible for actually creating the object (unless .CREATE called before and opaque object passed) and calling the BUILD routines. .BUILDALL - If it's still valid, http://dev.perl.org/perl6/rfc/189.html seems to cover the expected behavior of this. .BUILD - Used for object initialization, assigning passed named values (pairs) to object attributes if they match, or doing something more complex to initialize the object correctly based on supplied data. Some things to be wary of or that I'm still hazy on: What sort of calling syntax can be used in .new since the object isn't yet blessed? Or since .new encapsulates .bless (right?), I guess you can call normally AFTER the bless. .new happens before calling parent constructors, .BUILD happens after, so .new possibly won't have access to some default attributes as defined by parent classes/roles. Theoretically you could define a custom constructor, normalize data, call the regular .new constructor, and post process on the object returned before returning it yourself, I think. -- -Kevan Benson -A-1 Networks
Re: Custom object constructors
On Thu, Aug 20, 2009 at 10:44 PM, Kevan Benson wrote: > > > That said, I submit that it's a very confusing part of the language as > defined currently, and I haven't seen a very thorough explanation of the > purpose of each method in the chain the instantiates a new object. S12 > touches upon them slightly, but not in enough detail that I was able to work > out where I should be adding code to appropriately make alternate > constructors. Now that you apparently understand it, do you have a suggestion on how S12 might be phrased differently? I must admit that I don't quite grasp the concepts here yet, so an alternate wording might help others as well. Thanks for bringing the question up. -- Jan
Re: Custom object constructors
Moritz Lenz wrote: Kevan Benson wrote: Should there not be a way to define object constructors with custom signatures that can be usefully invoked like a normal constructor? Currently, defining a BUILD method for a class with a specific signature doesn't seem to allow for the object to be invoked by new with that signature and be correctly passed to the right BUILD method. It seems a whole chain of new -> bless -> BUILDALL -> BUILD would need to be defined with specific signatures just to get a custom constructor. No. It's enough to write a method .new that calls bless, which in turn calls BUILDALL (which re-dispatches to BUILD) (sorry if I got the order wrong in that IRC conversation). Let's assume we define default new() method with signature (*...@p, *%n) that passes positional arguments to BUILD as BUILD(|@p, |%n), then we might not be able to call BUILD submethods from superclasses (because they don't expect any positional parameters), so you basically loose compatibility with any super classes by introducing positional parameters. Not a good idea. It seems much more sane as it is now, that is to modify only the signature of new new() methods, not of BUILD methods. Okay, I can accept that. Most of my objections seemed to stem from misunderstanding what can be done in .new (or stated more succinctly, what can be done *easily* in .new). I was under the impression that since it was before bless, operations like calling methods on the object might be harder to do, but it's nothing that can't be worked around. That said, I submit that it's a very confusing part of the language as defined currently, and I haven't seen a very thorough explanation of the purpose of each method in the chain the instantiates a new object. S12 touches upon them slightly, but not in enough detail that I was able to work out where I should be adding code to appropriately make alternate constructors. -- -Kevan Benson -A-1 Networks
Re: Custom object constructors
Kevan Benson wrote: > Should there not be a way to define object constructors with custom > signatures that can be usefully invoked like a normal constructor? > > Currently, defining a BUILD method for a class with a specific signature > doesn't seem to allow for the object to be invoked by new with that > signature and be correctly passed to the right BUILD method. It seems a > whole chain of new -> bless -> BUILDALL -> BUILD would need to be > defined with specific signatures just to get a custom constructor. No. It's enough to write a method .new that calls bless, which in turn calls BUILDALL (which re-dispatches to BUILD) (sorry if I got the order wrong in that IRC conversation). Let's assume we define default new() method with signature (*...@p, *%n) that passes positional arguments to BUILD as BUILD(|@p, |%n), then we might not be able to call BUILD submethods from superclasses (because they don't expect any positional parameters), so you basically loose compatibility with any super classes by introducing positional parameters. Not a good idea. It seems much more sane as it is now, that is to modify only the signature of new new() methods, not of BUILD methods. Cheers, Moritz
Re: Custom object constructors
On 2009-Aug-19, at 4:37 pm, Kevan Benson wrote: I'm aware there's a default constructor that allows named parameters to be set, but I think the usefulness of allowing specific constructors that take defined parameters and initialize the object as needed should not be overlooked. E.g. my DateModule $d .= new('2007-03-12'); My first thought is also coercion: say my DateModule $d = '2007-03-12' and let DateModule::&.(Str) worry about making the new object. (Or does that need to be my DateModule $d = DateModule('2007-03-12')? That seems unnecessarily redundant.) -David
Re: Custom object constructors
Em Qua, 2009-08-19 às 15:37 -0700, Kevan Benson escreveu: > Should there not be a way to define object constructors with custom > signatures that can be usefully invoked like a normal constructor? What's the problem with method new(Str $timestamp) { self.SUPER::new(ts => strptime('...',$timestamp)); } ? > Currently, defining a BUILD method for a class with a specific signature > doesn't seem to allow for the object to be invoked by new with that > signature and be correctly passed to the right BUILD method. It seems a > whole chain of new -> bless -> BUILDALL -> BUILD would need to be > defined with specific signatures just to get a custom constructor. BUILD allows you to tweaken the initialization of known attributes. Your BUILD submethod will only receive then named arguments for the attributes locally defined in your class. The purpose of BUILD is *not* to provide alternative signatures to the constructor. > Two possible thoughts on how to achieve this were put forth in the > #perl6 discussion. One, auto build the chain on definition of a BUILD > method, which was thought be some to be a bit too magical (me included, > even though it was my suggestion at first). Alternatively, pass the > capture of arguments as supplied by new down the chain of initialization > methods so any that were defined as multi's can be called correctly by > multiple dispatch at the correct point. The bless-BUILDALL-BUILD chain uses the positional arguments as the candidate protoobjects that define additional parameters for the builders. the named parameters are passed to each BUILD method for initialization. Again, if you want a custom signature for new, just write a custom new. daniel
Re: Custom object constructors
I think the "too much magic" is in automatically creating the appropriate "new" method with that signature. I idea is to get the standard behavior, which is to define a method that's signature is used for the instantiation. Currently, I believe you have to define at least new and BUILD, not just one or the other. I guess you could redefine new and parse your arguments into the correct named pair arguments the other initialization functions (bless, BUILDALL, BUILD) expect, but that would be before blessing, and seems sort of limiting. Mark J. Reed wrote: I'm confused. The signature of initialize is used by Class.new in Ruby; the signature of __init__ is used by class_name() in Python... How is doing the same thing too much magic? Or am I misunderstanding the suggestion? On 8/19/09, Kevan Benson wrote: Should there not be a way to define object constructors with custom signatures that can be usefully invoked like a normal constructor? Currently, defining a BUILD method for a class with a specific signature doesn't seem to allow for the object to be invoked by new with that signature and be correctly passed to the right BUILD method. It seems a whole chain of new -> bless -> BUILDALL -> BUILD would need to be defined with specific signatures just to get a custom constructor. Two possible thoughts on how to achieve this were put forth in the #perl6 discussion. One, auto build the chain on definition of a BUILD method, which was thought be some to be a bit too magical (me included, even though it was my suggestion at first). Alternatively, pass the capture of arguments as supplied by new down the chain of initialization methods so any that were defined as multi's can be called correctly by multiple dispatch at the correct point. I'm aware there's a default constructor that allows named parameters to be set, but I think the usefulness of allowing specific constructors that take defined parameters and initialize the object as needed should not be overlooked. E.g. my DateModule $d .= new('2007-03-12'); Relevant bits of #perl6 discussion copied below: (2009-08-19 11:47:49) Kentrak: Q re: object initialization in p6; Should defining a BUILD with a non standard signature imply an implicit declaration of new with the same signature? (2009-08-19 11:48:05) moritz_: KyleHa: no (2009-08-19 11:48:23) moritz_: erm sorry, meant Kentrak (2009-08-19 11:48:26) moritz_: tab fail :/ (2009-08-19 11:48:35) moritz_: Kentrak: it's a nice idea, but it seems like too much magic to me (2009-08-19 11:48:50) Kentrak: moritz_: I'm aware it doesn't currently, but it seems like it really makes sense (2009-08-19 11:48:59) Kentrak: moritz_: in a DWIMmy sort of way (2009-08-19 11:49:28) moritz_: Kentrak: right, but I don't see how it fits in the current system without defining a huge exception (2009-08-19 11:49:29) r0bby left the room (quit: Read error: 104 (Connection reset by peer)). (2009-08-19 11:49:34) r0bby [n=wakaw...@guifications/user/r0bby] entered the room. (2009-08-19 11:49:43) __ash__: jnthn: http://gist.github.com/170571 (2009-08-19 11:49:51) Kentrak: moritz_: it seems I need to define a new() AND a BUILD() with matching signatures just to get the initialization syntax I want, soI might as well use new(), but then I have to cless... (2009-08-19 11:49:52) moritz_: anyway, I'll think about it (2009-08-19 11:50:02) Kentrak: err, bless (2009-08-19 11:50:15) moritz_: Kentrak: no, new() is enough, no need for another BUILD mofino molaf moritz_ mofino molaf moritz_ (2009-08-19 11:50:52) moritz_: well, maybe we could have a new() with slurpy positional arguments (2009-08-19 11:50:55) masak: I override new() when I want magic parameter handling, and BUILD when I want non-standard object initialization. (2009-08-19 11:50:56) japhb: moritz_, What are your rules of thumb for when to use the various ways (implicit and explicit) to define constructors? (2009-08-19 11:51:13) masak: #p6s in 10, by the way. (2009-08-19 11:51:28) dalek: rakudo: 5a85869 | pmichaud++ | docs/announce/2009-08: (2009-08-19 11:51:28) dalek: rakudo: Small fix to release announcement. (2009-08-19 11:51:28) dalek: rakudo: review: http://github.com/rakudo/rakudo/commit/5a85869ddbc17095cdb884f10a6cd1618804d773 (2009-08-19 11:51:31) moritz_: and have it try to dispatch to a BUILD method, and fail if there's no matching one (2009-08-19 11:51:37) jnthn: __ash__: OK, looks sane. (2009-08-19 11:51:41) jnthn: __ash__: Two questions (2009-08-19 11:51:42) Kentrak: moritz_: so if I want to add initializer methods to support something like my DateModule $d .= new('2007-03-12'); then I have to define new() submethods and use bless like in p5? (2009-08-19 11:51:47) jnthn: 1) Does it make what you wanted to work actually work? (2009-08-19 11:51:51) moritz_: japhb: sorry, I'm involved in too many things at a time, maybe I'll blog later about it (2009-08-19 11:51:55) jnthn: 2) Does it still pass the spectests? :-) (2009-08-19 11:51:58) japhb: moritz_, no
Re: Custom object constructors
I'm confused. The signature of initialize is used by Class.new in Ruby; the signature of __init__ is used by class_name() in Python... How is doing the same thing too much magic? Or am I misunderstanding the suggestion? On 8/19/09, Kevan Benson wrote: > > Should there not be a way to define object constructors with custom > signatures that can be usefully invoked like a normal constructor? > > Currently, defining a BUILD method for a class with a specific signature > doesn't seem to allow for the object to be invoked by new with that > signature and be correctly passed to the right BUILD method. It seems a > whole chain of new -> bless -> BUILDALL -> BUILD would need to be > defined with specific signatures just to get a custom constructor. > > Two possible thoughts on how to achieve this were put forth in the > #perl6 discussion. One, auto build the chain on definition of a BUILD > method, which was thought be some to be a bit too magical (me included, > even though it was my suggestion at first). Alternatively, pass the > capture of arguments as supplied by new down the chain of initialization > methods so any that were defined as multi's can be called correctly by > multiple dispatch at the correct point. > > I'm aware there's a default constructor that allows named parameters to > be set, but I think the usefulness of allowing specific constructors > that take defined parameters and initialize the object as needed should > not be overlooked. E.g. > my DateModule $d .= new('2007-03-12'); > > > > Relevant bits of #perl6 discussion copied below: > > (2009-08-19 11:47:49) Kentrak: Q re: object initialization in p6; Should > defining a BUILD with a non standard signature imply an implicit > declaration of new with the same signature? > (2009-08-19 11:48:05) moritz_: KyleHa: no > (2009-08-19 11:48:23) moritz_: erm sorry, meant Kentrak > (2009-08-19 11:48:26) moritz_: tab fail :/ > (2009-08-19 11:48:35) moritz_: Kentrak: it's a nice idea, but it seems > like too much magic to me > (2009-08-19 11:48:50) Kentrak: moritz_: I'm aware it doesn't currently, > but it seems like it really makes sense > (2009-08-19 11:48:59) Kentrak: moritz_: in a DWIMmy sort of way > (2009-08-19 11:49:28) moritz_: Kentrak: right, but I don't see how it > fits in the current system without defining a huge exception > (2009-08-19 11:49:29) r0bby left the room (quit: Read error: 104 > (Connection reset by peer)). > (2009-08-19 11:49:34) r0bby [n=wakaw...@guifications/user/r0bby] entered > the room. > (2009-08-19 11:49:43) __ash__: jnthn: http://gist.github.com/170571 > (2009-08-19 11:49:51) Kentrak: moritz_: it seems I need to define a > new() AND a BUILD() with matching signatures just to get the > initialization syntax I want, soI might as well use new(), but then I > have to cless... > (2009-08-19 11:49:52) moritz_: anyway, I'll think about it > (2009-08-19 11:50:02) Kentrak: err, bless > (2009-08-19 11:50:15) moritz_: Kentrak: no, new() is enough, no need for > another BUILD > mofino molaf moritz_ > mofino molaf moritz_ > (2009-08-19 11:50:52) moritz_: well, maybe we could have a new() with > slurpy positional arguments > (2009-08-19 11:50:55) masak: I override new() when I want magic > parameter handling, and BUILD when I want non-standard object > initialization. > (2009-08-19 11:50:56) japhb: moritz_, What are your rules of thumb for > when to use the various ways (implicit and explicit) to define constructors? > (2009-08-19 11:51:13) masak: #p6s in 10, by the way. > (2009-08-19 11:51:28) dalek: rakudo: 5a85869 | pmichaud++ | > docs/announce/2009-08: > (2009-08-19 11:51:28) dalek: rakudo: Small fix to release announcement. > (2009-08-19 11:51:28) dalek: rakudo: review: > http://github.com/rakudo/rakudo/commit/5a85869ddbc17095cdb884f10a6cd1618804d773 > (2009-08-19 11:51:31) moritz_: and have it try to dispatch to a BUILD > method, and fail if there's no matching one > (2009-08-19 11:51:37) jnthn: __ash__: OK, looks sane. > (2009-08-19 11:51:41) jnthn: __ash__: Two questions > (2009-08-19 11:51:42) Kentrak: moritz_: so if I want to add initializer > methods to support something like my DateModule $d .= new('2007-03-12'); > then I have to define new() submethods and use bless like in p5? > (2009-08-19 11:51:47) jnthn: 1) Does it make what you wanted to work > actually work? > (2009-08-19 11:51:51) moritz_: japhb: sorry, I'm involved in too many > things at a time, maybe I'll blog later about it > (2009-08-19 11:51:55) jnthn: 2) Does it still pass the spectests? :-) > (2009-08-19 11:51:58) japhb: moritz_, nod > (2009-08-19 11:52:11) masak: Kentrak: basically, yes. > (2009-08-19 11:52:12) moritz_: Kentrak: roughly, yes > (2009-08-19 11:52:37) jnthn: Kentrak: You'll generally want new to be > method, not submethod, though. > (2009-08-19 11:52:39) Kentrak: moritz_: actually, I assumed new() calls > BUILD(), does it? If it does, can't we just pass the same sig to BUILD > after blessing? > (2009-08-19 11:52:43) masak: Kentr
Custom object constructors
Should there not be a way to define object constructors with custom signatures that can be usefully invoked like a normal constructor? Currently, defining a BUILD method for a class with a specific signature doesn't seem to allow for the object to be invoked by new with that signature and be correctly passed to the right BUILD method. It seems a whole chain of new -> bless -> BUILDALL -> BUILD would need to be defined with specific signatures just to get a custom constructor. Two possible thoughts on how to achieve this were put forth in the #perl6 discussion. One, auto build the chain on definition of a BUILD method, which was thought be some to be a bit too magical (me included, even though it was my suggestion at first). Alternatively, pass the capture of arguments as supplied by new down the chain of initialization methods so any that were defined as multi's can be called correctly by multiple dispatch at the correct point. I'm aware there's a default constructor that allows named parameters to be set, but I think the usefulness of allowing specific constructors that take defined parameters and initialize the object as needed should not be overlooked. E.g. my DateModule $d .= new('2007-03-12'); Relevant bits of #perl6 discussion copied below: (2009-08-19 11:47:49) Kentrak: Q re: object initialization in p6; Should defining a BUILD with a non standard signature imply an implicit declaration of new with the same signature? (2009-08-19 11:48:05) moritz_: KyleHa: no (2009-08-19 11:48:23) moritz_: erm sorry, meant Kentrak (2009-08-19 11:48:26) moritz_: tab fail :/ (2009-08-19 11:48:35) moritz_: Kentrak: it's a nice idea, but it seems like too much magic to me (2009-08-19 11:48:50) Kentrak: moritz_: I'm aware it doesn't currently, but it seems like it really makes sense (2009-08-19 11:48:59) Kentrak: moritz_: in a DWIMmy sort of way (2009-08-19 11:49:28) moritz_: Kentrak: right, but I don't see how it fits in the current system without defining a huge exception (2009-08-19 11:49:29) r0bby left the room (quit: Read error: 104 (Connection reset by peer)). (2009-08-19 11:49:34) r0bby [n=wakaw...@guifications/user/r0bby] entered the room. (2009-08-19 11:49:43) __ash__: jnthn: http://gist.github.com/170571 (2009-08-19 11:49:51) Kentrak: moritz_: it seems I need to define a new() AND a BUILD() with matching signatures just to get the initialization syntax I want, soI might as well use new(), but then I have to cless... (2009-08-19 11:49:52) moritz_: anyway, I'll think about it (2009-08-19 11:50:02) Kentrak: err, bless (2009-08-19 11:50:15) moritz_: Kentrak: no, new() is enough, no need for another BUILD mofino molaf moritz_ mofino molaf moritz_ (2009-08-19 11:50:52) moritz_: well, maybe we could have a new() with slurpy positional arguments (2009-08-19 11:50:55) masak: I override new() when I want magic parameter handling, and BUILD when I want non-standard object initialization. (2009-08-19 11:50:56) japhb: moritz_, What are your rules of thumb for when to use the various ways (implicit and explicit) to define constructors? (2009-08-19 11:51:13) masak: #p6s in 10, by the way. (2009-08-19 11:51:28) dalek: rakudo: 5a85869 | pmichaud++ | docs/announce/2009-08: (2009-08-19 11:51:28) dalek: rakudo: Small fix to release announcement. (2009-08-19 11:51:28) dalek: rakudo: review: http://github.com/rakudo/rakudo/commit/5a85869ddbc17095cdb884f10a6cd1618804d773 (2009-08-19 11:51:31) moritz_: and have it try to dispatch to a BUILD method, and fail if there's no matching one (2009-08-19 11:51:37) jnthn: __ash__: OK, looks sane. (2009-08-19 11:51:41) jnthn: __ash__: Two questions (2009-08-19 11:51:42) Kentrak: moritz_: so if I want to add initializer methods to support something like my DateModule $d .= new('2007-03-12'); then I have to define new() submethods and use bless like in p5? (2009-08-19 11:51:47) jnthn: 1) Does it make what you wanted to work actually work? (2009-08-19 11:51:51) moritz_: japhb: sorry, I'm involved in too many things at a time, maybe I'll blog later about it (2009-08-19 11:51:55) jnthn: 2) Does it still pass the spectests? :-) (2009-08-19 11:51:58) japhb: moritz_, nod (2009-08-19 11:52:11) masak: Kentrak: basically, yes. (2009-08-19 11:52:12) moritz_: Kentrak: roughly, yes (2009-08-19 11:52:37) jnthn: Kentrak: You'll generally want new to be method, not submethod, though. (2009-08-19 11:52:39) Kentrak: moritz_: actually, I assumed new() calls BUILD(), does it? If it does, can't we just pass the same sig to BUILD after blessing? (2009-08-19 11:52:43) masak: Kentrak: .CREATE and .bless is how you create objects in Perl 6. (2009-08-19 11:53:04) masak: Kentrak: I think .bless calls BUILDALL, which calls BUILD. (2009-08-19 11:53:10) jnthn: .bless will trigger...yes, what masak said. (2009-08-19 11:53:17) moritz_: pmichaud: funny, I had the exact same fixes, byte by byte ;-) (2009-08-19 11:53:18) Kentrak: masak: Hmm, I'm finding the