digitalmars.D - 'new' class method
- bearophile (40/40) Oct 23 2008 In Python to create new instances of a class you use the normal function...
- Bill Baxter (7/45) Oct 23 2008 I like it. Can we get rid of delete's specialness too?
- Yigal Chripun (9/59) Oct 23 2008 Andrei already mentioned that he wants to get read of new/delete IIRC.
- Bill Baxter (12/71) Oct 23 2008 Hmm, I didn't realize D had a placement new. But clearly it does and
- dsimcha (5/64) Oct 23 2008 One thing I would definitely like to see is for struct and class syntax ...
- Bill Baxter (9/73) Oct 23 2008 To me this makes a lot of sense:
- Steven Schveighoffer (6/13) Oct 23 2008 It also cleans up this ugliness:
- Bill Baxter (24/39) Oct 23 2008 But, ok, this isn't Python so we have to have a story for placement new.
- bearophile (16/28) Oct 23 2008 I agree that the placement new syntax can be less nice.
- Bill Baxter (58/84) Oct 23 2008 Well, D tries to make heap classes look syntactically the same stack
- Sergey Gromov (4/8) Oct 23 2008 Maybe do it with a library function?
- Bill Baxter (4/12) Oct 23 2008 The current placement new in D can take an arbitrary list of args. So
- KennyTM~ (4/19) Oct 23 2008 Can a library function return a constructor? Like this:
- Sergey Gromov (14/36) Oct 24 2008 It shouldn't be easy to call a constructor directly--you don't want to d...
- Benji Smith (23/36) Oct 23 2008 I don't particularly care about getting rid of the "new" keyword. In
- Bill Baxter (11/47) Oct 24 2008 Did you see my subsequent proposal? I'm actually quite fond of it.
- Benji Smith (28/38) Oct 24 2008 You mean the one where you suggested this?
- KennyTM~ (28/80) Oct 24 2008 I strongly *oppose* using stack and heap as keywords because there are
- Bill Baxter (57/106) Oct 24 2008 Right, that's why both Benji and I proposed making them *context*
- Benji Smith (30/74) Oct 24 2008 Agree with you 1000%.
- KennyTM~ (9/149) Oct 25 2008 I see. But with the your new(...) syntax this can't be done because it
- KennyTM~ (4/40) Oct 25 2008 or do it like this:
- Yigal Chripun (9/52) Oct 25 2008 maybe just add the concept of allocators.
- KennyTM~ (3/54) Oct 25 2008 This can't work because parameters (I bet you mean constructor arguments...
- Yigal Chripun (17/73) Oct 25 2008 I did mean the constructor arguments. The syntax itself is less
- KennyTM~ (5/82) Oct 25 2008 Yes. Although the problem right now is syntactical. :(
- Yigal Chripun (15/105) Oct 25 2008 if there's an allocator object, you don't need the above. just pass the
- KennyTM~ (11/116) Oct 25 2008 What if the constructor may take the allocator object as its argument?
- Bill Baxter (16/29) Oct 25 2008 Yeh, I was thinking that was a possibility too, if .new(heap,a)
- dsimcha (27/28) Oct 23 2008 Actually, I sometimes use static opCall to encapsulate the creation of t...
- Bill Baxter (7/35) Oct 23 2008 There are definitely uses for static opCall, but it's all just for
- Bill Baxter (12/71) Oct 23 2008 Hmm, I didn't realize D had a placement new. But clearly it does and
In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3); With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding. Bye, bearophile
Oct 23 2008
On Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008
Bill Baxter wrote:On Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:Andrei already mentioned that he wants to get read of new/delete IIRC. I like Ruby's way of making it regular methods. something like: obj.new(..) and obj.delete() but, how do you specify stack vs heap allocation? something like: auto a = new S(); //on heap auto b = S(); //on stack also, what about placement new?In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008
On Thu, Oct 23, 2008 at 8:47 PM, Yigal Chripun <yigal100 gmail.com> wrote:Bill Baxter wrote:Hmm, I didn't realize D had a placement new. But clearly it does and more -- you can pass args to new to control the allocator. http://www.digitalmars.com/d/2.0/class.html look for "Class Allocators". also http://www.digitalmars.com/d/2.0/memory.html#newdelete So simply saying make it Obj.new(args) won't cut it. You need to be able to do something like Obj.new(newargs)(constructorargs) also. --bbOn Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:Andrei already mentioned that he wants to get read of new/delete IIRC. I like Ruby's way of making it regular methods. something like: obj.new(..) and obj.delete() but, how do you specify stack vs heap allocation? something like: auto a = new S(); //on heap auto b = S(); //on stack also, what about placement new?In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008
== Quote from Yigal Chripun (yigal100 gmail.com)'s articleBill Baxter wrote:One thing I would definitely like to see is for struct and class syntax to be unified so that if you change a struct to a class or vice versa, this doesn't require changes all over your code. Then again, the reference vs. value semantic issue may bite you anyhow.On Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:Andrei already mentioned that he wants to get read of new/delete IIRC. I like Ruby's way of making it regular methods. something like: obj.new(..) and obj.delete() but, how do you specify stack vs heap allocation? something like: auto a = new S(); //on heap auto b = S(); //on stack also, what about placement new?In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008
On Thu, Oct 23, 2008 at 9:26 PM, dsimcha <dsimcha yahoo.com> wrote:== Quote from Yigal Chripun (yigal100 gmail.com)'s articleTo me this makes a lot of sense: auto a = SomeStruct(); // a is a struct on the stack auto b = SomeClass(); // b is a class on the heap It kills static opCall for classes, but who cares. I'm often tempted to write static opCalls for classes like this anyway: static SomeClass opCall() { return new SomeClass(); } Just to get the uniformity of construction syntax. --bbBill Baxter wrote:One thing I would definitely like to see is for struct and class syntax to be unified so that if you change a struct to a class or vice versa, this doesn't require changes all over your code. Then again, the reference vs. value semantic issue may bite you anyhow.On Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:Andrei already mentioned that he wants to get read of new/delete IIRC. I like Ruby's way of making it regular methods. something like: obj.new(..) and obj.delete() but, how do you specify stack vs heap allocation? something like: auto a = new S(); //on heap auto b = S(); //on stack also, what about placement new?In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008
"Bill Baxter" wroteTo me this makes a lot of sense: auto a = SomeStruct(); // a is a struct on the stack auto b = SomeClass(); // b is a class on the heap It kills static opCall for classes, but who cares. I'm often tempted to write static opCalls for classes like this anyway: static SomeClass opCall() { return new SomeClass(); } Just to get the uniformity of construction syntax.It also cleans up this ugliness: auto data = (new FileInput(filename)).readAll(); Which then becomes: auto data = FileInput(filename).readAll(); -Steve
Oct 23 2008
On Fri, Oct 24, 2008 at 5:07 AM, Steven Schveighoffer <schveiguy yahoo.com> wrote:"Bill Baxter" wroteBut, ok, this isn't Python so we have to have a story for placement new. I believe use of placement new is pretty rare. (I use it rarely, anyway. :-) ) If so it should be ok if the syntax is a little clunky. Also heap construction of structs. How about this as a start: // Default cases auto a = SomeStruct(arg); // struct on the stack auto a = SomeClass(arg); // class on the heap // Anti-default cases auto a = SomeStruct.new(arg); // struct on the heap scope a = SomeClass(arg); // class on the stack // Placement cases auto a = SomeStruct.new[placement_arg](arg); // placement struct auto a = SomeClass.new[placement_arg](arg); // placement class Not sure about those brackets. Kind of odd-ball, but placement new is kind of odd-ball anyway. And I think we agreed that such syntax was workable for templates, if not pleasant for the programmer. But new expressions are rarely part of mondo compound expressions, and there's the keyword "new" to clue you in, so I think it should be acceptable in this case. --bbTo me this makes a lot of sense: auto a = SomeStruct(); // a is a struct on the stack auto b = SomeClass(); // b is a class on the heap It kills static opCall for classes, but who cares. I'm often tempted to write static opCalls for classes like this anyway: static SomeClass opCall() { return new SomeClass(); } Just to get the uniformity of construction syntax.It also cleans up this ugliness: auto data = (new FileInput(filename)).readAll(); Which then becomes: auto data = FileInput(filename).readAll();
Oct 23 2008
Bill Baxter:How about this as a start: // Default cases auto a = SomeStruct(arg); // struct on the stack auto a = SomeClass(arg); // class on the heap // Anti-default cases auto a = SomeStruct.new(arg); // struct on the heap scope a = SomeClass(arg); // class on the stack // Placement cases ...I agree that the placement new syntax can be less nice. But for the struct/class cases I'd like something more symmetric :-) A first silly possibility: auto a = SomeStruct(arg); // stack auto a = SomeStruct.new(arg); // heap auto a = SomeStruct.pnew(placement_arg)(arg); // placement A possible alternative: auto a = SomeStruct.pnew(placement_arg).new(arg); // placement auto a = SomeClass(arg); // stack auto a = SomeClass.new(arg); // heap auto a = SomeClass.pnew(placement_arg)(arg); // placement A possible alternative: auto a = SomeClass.pnew(placement_arg).new(arg); // placement Bye, bearophile
Oct 23 2008
On Fri, Oct 24, 2008 at 5:44 AM, bearophile <bearophileHUGS lycos.com> wrote:Bill Baxter:Well, D tries to make heap classes look syntactically the same stack structs in most cases despite the semantic differences. "Foo x" is either a stack struct or a heap class. The 'x' does not look like a pointer if it's a class, but in fact it is a pointer. That was D's big change over C++ -- make the *default* case for those two use the same syntax. So I don't see why construction should be the only place to put that distinction in your face. The default syntaxes look the same elsewhere, so the default scheme for construction should look the same for both. Such uniformity is also going to be better for writing templates that construct things. Structs are more likely to be pure value types than classes. So if I want to write a template that does non-default construction of an array of Things I'd rather be able to write this: Thing[] make_thing_array(Thing, ConstructArgs...)(size_t len, ConstructArgs A) { Thing[] ret; ret.length = len; foreach(ref o; ret) { o = Thing(A); } } Than have to resort to static ifs all the time just to get the default behavior: Thing[] make_thing_array(Thing, ConstructArgs...)(size_t len, ConstructArgs A) { Thing[] ret; ret.length = len; static if(is(Thing : class)) { foreach(ref o; ret) { o = new Thing(A); } } else { foreach(ref o; ret) { o = Thing(A); } } } Put another way, I think the case of "give me default allocation for the type" is more common in generic code than "give me heap allocation no matter what". So for me, the main thing I care about is making the *default* allocation strategy use the same syntax. Beyond that I don't really care much what syntax is chosen. ... But here's another thought. It doesn't really have to be me vs you here. Both cases do have some use. Maybe the best thing here is a syntax that can *either* emphasize sameness of allocation *or* emphasize default behavior. So then: auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placement One thing to consider is that anything other than the default strategy is really a kind of a vague placement new. You're telling the compiler to construct the object in some non-default memory location, you're just not telling it exactly what the address is, just whether the address should be in heap or stack. In the above "heap" and "stack" are context keywords of new. --bbHow about this as a start: // Default cases auto a = SomeStruct(arg); // struct on the stack auto a = SomeClass(arg); // class on the heap // Anti-default cases auto a = SomeStruct.new(arg); // struct on the heap scope a = SomeClass(arg); // class on the stack // Placement cases ...I agree that the placement new syntax can be less nice. But for the struct/class cases I'd like something more symmetric :-) A first silly possibility: auto a = SomeStruct(arg); // stack auto a = SomeStruct.new(arg); // heap auto a = SomeStruct.pnew(placement_arg)(arg); // placement A possible alternative: auto a = SomeStruct.pnew(placement_arg).new(arg); // placement auto a = SomeClass(arg); // stack auto a = SomeClass.new(arg); // heap auto a = SomeClass.pnew(placement_arg)(arg); // placement A possible alternative: auto a = SomeClass.pnew(placement_arg).new(arg); // placement
Oct 23 2008
Fri, 24 Oct 2008 05:31:44 +0900, Bill Baxter wrote:But, ok, this isn't Python so we have to have a story for placement new. I believe use of placement new is pretty rare. (I use it rarely, anyway. :-) ) If so it should be ok if the syntax is a little clunky.Maybe do it with a library function? auto c = core.intrinsic.construct!(C)(addr, ctor_arg0, ctor_arg1);
Oct 23 2008
On Fri, Oct 24, 2008 at 6:28 AM, Sergey Gromov <snake.scaly gmail.com> wrote:Fri, 24 Oct 2008 05:31:44 +0900, Bill Baxter wrote:The current placement new in D can take an arbitrary list of args. So you have two lists -- new_args and ctor_args. --bbBut, ok, this isn't Python so we have to have a story for placement new. I believe use of placement new is pretty rare. (I use it rarely, anyway. :-) ) If so it should be ok if the syntax is a little clunky.Maybe do it with a library function? auto c = core.intrinsic.construct!(C)(addr, ctor_arg0, ctor_arg1);
Oct 23 2008
Bill Baxter wrote:On Fri, Oct 24, 2008 at 6:28 AM, Sergey Gromov <snake.scaly gmail.com> wrote:Can a library function return a constructor? Like this: auto c = core.intrinsic.construct!(C)(addr, new_args...)(ctor_args ...); But that's similar to C.new(addr, new_args...)(ctor_args...);Fri, 24 Oct 2008 05:31:44 +0900, Bill Baxter wrote:The current placement new in D can take an arbitrary list of args. So you have two lists -- new_args and ctor_args. --bbBut, ok, this isn't Python so we have to have a story for placement new. I believe use of placement new is pretty rare. (I use it rarely, anyway. :-) ) If so it should be ok if the syntax is a little clunky.Maybe do it with a library function? auto c = core.intrinsic.construct!(C)(addr, ctor_arg0, ctor_arg1);
Oct 23 2008
Fri, 24 Oct 2008 14:32:23 +0800, KennyTM~ wrote:Bill Baxter wrote:It shouldn't be easy to call a constructor directly--you don't want to do it by accident. Current new semantics automates and hides a lot of stuff under the hood: * calculates the required size * calls an allocator of the class to be constructed, choosing the allocator according to overloading rules * calls a constructor for the same class, choosing the constructor according to overloading rules * converts the results into a class reference In theory, if you drop part of this automation, it's sufficient to have a built-in function that calls a constructor on an arbitrary memory and returns a reference to the constructed object.On Fri, Oct 24, 2008 at 6:28 AM, Sergey Gromov <snake.scaly gmail.com> wrote:Can a library function return a constructor? Like this: auto c = core.intrinsic.construct!(C)(addr, new_args...)(ctor_args ...); But that's similar to C.new(addr, new_args...)(ctor_args...);Fri, 24 Oct 2008 05:31:44 +0900, Bill Baxter wrote:The current placement new in D can take an arbitrary list of args. So you have two lists -- new_args and ctor_args. --bbBut, ok, this isn't Python so we have to have a story for placement new. I believe use of placement new is pretty rare. (I use it rarely, anyway. :-) ) If so it should be ok if the syntax is a little clunky.Maybe do it with a library function? auto c = core.intrinsic.construct!(C)(addr, ctor_arg0, ctor_arg1);
Oct 24 2008
Bill Baxter wrote:How about this as a start: // Default cases auto a = SomeStruct(arg); // struct on the stack auto a = SomeClass(arg); // class on the heap // Anti-default cases auto a = SomeStruct.new(arg); // struct on the heap scope a = SomeClass(arg); // class on the stack // Placement cases auto a = SomeStruct.new[placement_arg](arg); // placement struct auto a = SomeClass.new[placement_arg](arg); // placement classI don't particularly care about getting rid of the "new" keyword. In fact, I especially like the part about getting rid of this little ugly: // uuuuuugly auto x = (new MyClass()).whatever(); // holy crap. so much better. auto x = MyClass().whatever(); But I think it's weird that people want to retain "new" to indicate heap construction and use the word "scope" to indicate stack construction. Except for structs, which would have different rules. Ugh. Why not just introduce "heap" and "stack" keywords, and say it directly? stack auto x = MyClass(); heap auto y = MyStruct(); ...or, since "heap" and "stack" are good user keywords, maybe introduce an "on" keyword. Maybe something like this: auto x = on(stack) MyClass(); auto y = on(heap) MyStruct(); To me, there's nothing about the "new" keyword that implies heap construction. "Scope" is a little bit better, because I know the memory will be cleaned up at the end of the scope, but that doesn't *necessarily* mean stack allocation, per se. --benji
Oct 23 2008
On Fri, Oct 24, 2008 at 3:01 PM, Benji Smith <dlanguage benjismith.net> wrote:Bill Baxter wrote:Did you see my subsequent proposal? I'm actually quite fond of it. But no one has responded to it. :-( [Bill cry's himself a silent tear.]How about this as a start: // Default cases auto a = SomeStruct(arg); // struct on the stack auto a = SomeClass(arg); // class on the heap // Anti-default cases auto a = SomeStruct.new(arg); // struct on the heap scope a = SomeClass(arg); // class on the stack // Placement cases auto a = SomeStruct.new[placement_arg](arg); // placement struct auto a = SomeClass.new[placement_arg](arg); // placement classI don't particularly care about getting rid of the "new" keyword. In fact, I especially like the part about getting rid of this little ugly: // uuuuuugly auto x = (new MyClass()).whatever(); // holy crap. so much better. auto x = MyClass().whatever(); But I think it's weird that people want to retain "new" to indicate heap construction and use the word "scope" to indicate stack construction. Except for structs, which would have different rules. Ugh. Why not just introduce "heap" and "stack" keywords, and say it directly?stack auto x = MyClass(); heap auto y = MyStruct(); ...or, since "heap" and "stack" are good user keywords, maybe introduce an "on" keyword. Maybe something like this: auto x = on(stack) MyClass(); auto y = on(heap) MyStruct();That's kinda cute. "in" would almost work there. Too bad we don't usually say "put it in the stack" in CS. :-)To me, there's nothing about the "new" keyword that implies heap construction. "Scope" is a little bit better, because I know the memory will be cleaned up at the end of the scope, but that doesn't *necessarily* mean stack allocation, per se.New is already a keyword meaning allocation/construction in D, Java, that "new" probably has something to do with construction. So the question is why wouldn't you use "new"? --bb
Oct 24 2008
Bill Baxter wrote:On Fri, Oct 24, 2008 at 3:01 PM, Benji Smith <dlanguage benjismith.net> wrote:You mean the one where you suggested this? auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placement Yeah! I noticed it. And I like it. In fact, I thought to myself "that's almost the same as my idea". Generally, I'm not a fan of the consecutive sequence of parentheses (especially that templates already make for double parens; I can't imagine I'd want triple parens for a templatized consttructor call). For non-template chained calls, I'm not quite sure which I prefer: auto a = Foo.new(heap)(Bar.new(stack)()); auto a = on(heap) Foo(on(stack) Bar());Why not just introduce "heap" and "stack" keywords, and say it directly?Did you see my subsequent proposal? I'm actually quite fond of it. But no one has responded to it. :-( [Bill cry's himself a silent tear.]New is already a keyword meaning allocation/construction in D, Java, that "new" probably has something to do with construction. So the question is why wouldn't you use "new"?structs can *only* be allocated on the stack (unless they're members of an object, or if they're in an array). To me, "new" is a great word for "allocate, and then invoke the constructor", but it doesn't have anything to do with *HEAP* allocation, per se. And then I thought to myself "for chrissakes, if you want the heap or the stack, why not ask for it by name?" --benji
Oct 24 2008
Benji Smith wrote:Bill Baxter wrote:I strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap. And I think we can include the meaning that “scope” attribute always allocate on stack (Currently 4 conditions need to be met for so), but I'm afraid this may break something (otherwise the other 3 conditions won't be there?). Maybe some experts can comment on this? (Ref: http://www.digitalmars.com/d/2.0/memory.html#stackclass) And I suggest keeping the “new” syntax for heap ("return a pointer") allocation. So, auto c = Class(...); // default on heap auto s = Struct(...); // default on stack (compatible with current syntax) scope c = Class(...); // on stack scope s = Struct(...); // on stack (compatible with current syntax) auto c = new Class(...); // on heap (compatible with current syntax) auto s = new Struct(...); // on heap (compatible with current syntax) auto c = new(...) Class(...); // placement (compatible with current syntax) auto s = new(...) Struct(...); // placement (compatible with current syntax?) /* if you want symmetry, do it like this: new c = Class(...); new(...) c = Class(...); kinda strange for me. */ These will cause minimum change while eliminating the “new” for most cases. This won't free the “new” keyword though.On Fri, Oct 24, 2008 at 3:01 PM, Benji Smith <dlanguage benjismith.net> wrote:You mean the one where you suggested this? auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementWhy not just introduce "heap" and "stack" keywords, and say it directly?Did you see my subsequent proposal? I'm actually quite fond of it. But no one has responded to it. :-( [Bill cry's himself a silent tear.]Yeah! I noticed it. And I like it. In fact, I thought to myself "that's almost the same as my idea". Generally, I'm not a fan of the consecutive sequence of parentheses (especially that templates already make for double parens; I can't imagine I'd want triple parens for a templatized consttructor call). For non-template chained calls, I'm not quite sure which I prefer: auto a = Foo.new(heap)(Bar.new(stack)()); auto a = on(heap) Foo(on(stack) Bar());New is already a keyword meaning allocation/construction in D, Java, that "new" probably has something to do with construction. So the question is why wouldn't you use "new"?structs can *only* be allocated on the stack (unless they're members of an object, or if they're in an array). To me, "new" is a great word for "allocate, and then invoke the constructor", but it doesn't have anything to do with *HEAP* allocation, per se. And then I thought to myself "for chrissakes, if you want the heap or the stack, why not ask for it by name?" --benji
Oct 24 2008
On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.And I think we can include the meaning that "scope" attribute always allocate on stack (Currently 4 conditions need to be met for so), but I'm afraid this may break something (otherwise the other 3 conditions won't be there?). Maybe some experts can comment on this?And I suggest keeping the "new" syntax for heap ("return a pointer") allocation. So,Well, Andrei was looking at getting rid of this "new blah" syntax for other reasons already, so that's why I tacked in on as a pseudomethod of classes and structs.auto c = Class(...); // default on heap auto s = Struct(...); // default on stack (compatible with current syntax) scope c = Class(...); // on stack scope s = Struct(...); // on stack (compatible with current syntax)The main thing I don't like about this syntax is that it makes it impossible to create a class temporary on the stack in an expressoin. It means you always have to declare it and give it a name if you want to avoid the heap. It's just not orthogonal in that way. As in it entangles construction with declaration, when those two are usually separate concerns. Specifically as an example, say you have some object that does comparisions and you want to pass it to a sort function then uniq it . First you wrote this: T[] array; ... T[] filtered = uniq(sorted(MyComparator.new, array))); Then you decided the heap alloc was unnecessary there, so now you have to change it all around T[] array; ... { // made a block here so that theComparator goes away after sorting scope theComparator = MyComparator.new; T[] filtered = uniq(sorted(theComparator, array))); } Instead of just sticking "(stack)" in there and being done with it: T[] array; ... T[] filtered = uniq(sorted(MyComparator.new(stack), array)));auto c = new Class(...); // on heap (compatible with current syntax) auto s = new Struct(...); // on heap (compatible with current syntax) auto c = new(...) Class(...); // placement (compatible with current syntax) auto s = new(...) Struct(...); // placement (compatible with current syntax?) /* if you want symmetry, do it like this: new c = Class(...); new(...) c = Class(...); kinda strange for me. */Yeh, me too. I definitely don't want any more of this sillyness of mixing up construction with declaration.These will cause minimum change while eliminating the "new" for most cases. This won't free the "new" keyword though.I don't particularly think it needs to be freed up. A better case may be made for, delete, though because there's less that's special about how it works.(To Benji now) Yep, it was!Yeah! I noticed it. And I like it. In fact, I thought to myself "that's almost the same as my idea".Well, the idea is that the versions that use "new" will be fairly rare. I'm certainly open to other ideas. I suggested using [] just for new args in another post. Like MyClass.new[scope](foo,bar) It just seems odd to me to use that in this one place and no other. I think the parens would work, which is why I went back to parens. Another possibility might be to introduce some syntax for heap vs stack and only use () for placement new -- like this: Class.*new(construct_args); // stack (like *foo is dereferenced foo pointer) Struct.*new(construct_args); // stack Class.new(construct_args); // heap Struct.new(construct_args); // heap Class.new (new_args)(construct_args); // placement Struct.new (new_args)(construct_args); // placementGenerally, I'm not a fan of the consecutive sequence of parentheses (especially that templates already make for double parens; I can't imagine I'd want triple parens for a templatized consttructor call).I think Andrei is gunning to get rid of the dangling prefix words in the grammar. That's why I put .new at the end. I think he would also be happy with a regular function-like syntax, too, but what I've seen of that looks ugly. When you do 'new' there always a class or struct involved, so why not make it a pseudo property of every class and struct, just like .init or .tupleof? --bbFor non-template chained calls, I'm not quite sure which I prefer: auto a = Foo.new(heap)(Bar.new(stack)()); auto a = on(heap) Foo(on(stack) Bar());
Oct 24 2008
Bill Baxter wrote:Agree with you 1000%. This is one of my minor annoyances with D. Static arrays and structs must be constructed in a statement, rather than in an expression like everything else. MyStruct s; // why can't a MyStruct be created in an expression? float[3] f; // same deal here! what gives? I'd very much like to see a little more unification in construction semantics, among classes, structs, and all the different types of arrays. For one thing, if construction semantics was more unified, it'd be much more straightforward to "upgrade" certain bits of code if/when you decide to switch from a struct implementation to a class (or vice versa). It'd probably also be simpler to write certain kinds of templates (though no examples spring to mind right now). Anyhow, If this business of getting rid of "new" is a step in that direction, I'm all for it.auto c = Class(...); // default on heap auto s = Struct(...); // default on stack (compatible with current syntax) scope c = Class(...); // on stack scope s = Struct(...); // on stack (compatible with current syntax)The main thing I don't like about this syntax is that it makes it impossible to create a class temporary on the stack in an expressoin. It means you always have to declare it and give it a name if you want to avoid the heap. It's just not orthogonal in that way. As in it entangles construction with declaration, when those two are usually separate concerns.Ditto./* if you want symmetry, do it like this: new c = Class(...); new(...) c = Class(...); kinda strange for me. */Yeh, me too. I definitely don't want any more of this sillyness of mixing up construction with declaration.Another possibility might be to introduce some syntax for heap vs stack and only use () for placement new -- like this: Class.*new(construct_args); // stack (like *foo is dereferenced foo pointer) Struct.*new(construct_args); // stack Class.new(construct_args); // heap Struct.new(construct_args); // heap Class.new (new_args)(construct_args); // placement Struct.new (new_args)(construct_args); // placementHmmmmmm. Nope. I'll know it when I see it, but this is definitely not it :)Maybe... It still doesn't seem quite right, though. Really, it's the GC that's doing the allocating, so the "new" function ought to belong to the GC object, and the constructor could be a delegate passed to the GC... auto x = GC.new(&Constructor); I admit, I don't really like that either :o( But at least it makes it a little clearer what's going on than the Foo.new()() syntax. Back to the drawing board!!! --benjiI think Andrei is gunning to get rid of the dangling prefix words in the grammar. That's why I put .new at the end. I think he would also be happy with a regular function-like syntax, too, but what I've seen of that looks ugly. When you do 'new' there always a class or struct involved, so why not make it a pseudo property of every class and struct, just like .init or .tupleof?For non-template chained calls, I'm not quite sure which I prefer: auto a = Foo.new(heap)(Bar.new(stack)()); auto a = on(heap) Foo(on(stack) Bar());
Oct 24 2008
Bill Baxter wrote:On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.I know. My suggestion is not to get rid of all the new syntax but make it appear less frequently.And I think we can include the meaning that "scope" attribute always allocate on stack (Currently 4 conditions need to be met for so), but I'm afraid this may break something (otherwise the other 3 conditions won't be there?). Maybe some experts can comment on this?And I suggest keeping the "new" syntax for heap ("return a pointer") allocation. So,Well, Andrei was looking at getting rid of this "new blah" syntax for other reasons already, so that's why I tacked in on as a pseudomethod of classes and structs.I see. So seems we must stick with method calls.auto c = Class(...); // default on heap auto s = Struct(...); // default on stack (compatible with current syntax) scope c = Class(...); // on stack scope s = Struct(...); // on stack (compatible with current syntax)The main thing I don't like about this syntax is that it makes it impossible to create a class temporary on the stack in an expressoin. It means you always have to declare it and give it a name if you want to avoid the heap. It's just not orthogonal in that way. As in it entangles construction with declaration, when those two are usually separate concerns. Specifically as an example, say you have some object that does comparisions and you want to pass it to a sort function then uniq it . First you wrote this: T[] array; ... T[] filtered = uniq(sorted(MyComparator.new, array))); Then you decided the heap alloc was unnecessary there, so now you have to change it all around T[] array; ... { // made a block here so that theComparator goes away after sorting scope theComparator = MyComparator.new; T[] filtered = uniq(sorted(theComparator, array))); } Instead of just sticking "(stack)" in there and being done with it: T[] array; ... T[] filtered = uniq(sorted(MyComparator.new(stack), array)));auto c = new Class(...); // on heap (compatible with current syntax) auto s = new Struct(...); // on heap (compatible with current syntax) auto c = new(...) Class(...); // placement (compatible with current syntax) auto s = new(...) Struct(...); // placement (compatible with current syntax?) /* if you want symmetry, do it like this: new c = Class(...); new(...) c = Class(...); kinda strange for me. */Yeh, me too. I definitely don't want any more of this sillyness of mixing up construction with declaration.These will cause minimum change while eliminating the "new" for most cases. This won't free the "new" keyword though.I don't particularly think it needs to be freed up. A better case may be made for, delete, though because there's less that's special about how it works.(To Benji now) Yep, it was!Yeah! I noticed it. And I like it. In fact, I thought to myself "that's almost the same as my idea".Well, the idea is that the versions that use "new" will be fairly rare. I'm certainly open to other ideas. I suggested using [] just for new args in another post. Like MyClass.new[scope](foo,bar) It just seems odd to me to use that in this one place and no other. I think the parens would work, which is why I went back to parens. Another possibility might be to introduce some syntax for heap vs stack and only use () for placement new -- like this: Class.*new(construct_args); // stack (like *foo is dereferenced foo pointer) Struct.*new(construct_args); // stack Class.new(construct_args); // heap Struct.new(construct_args); // heap Class.new (new_args)(construct_args); // placement Struct.new (new_args)(construct_args); // placementGenerally, I'm not a fan of the consecutive sequence of parentheses (especially that templates already make for double parens; I can't imagine I'd want triple parens for a templatized consttructor call).I think Andrei is gunning to get rid of the dangling prefix words in the grammar. That's why I put .new at the end. I think he would also be happy with a regular function-like syntax, too, but what I've seen of that looks ugly. When you do 'new' there always a class or struct involved, so why not make it a pseudo property of every class and struct, just like .init or .tupleof? --bbFor non-template chained calls, I'm not quite sure which I prefer: auto a = Foo.new(heap)(Bar.new(stack)()); auto a = on(heap) Foo(on(stack) Bar());
Oct 25 2008
KennyTM~ wrote:Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.
Oct 25 2008
KennyTM~ wrote:KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.
Oct 25 2008
Yigal Chripun wrote:KennyTM~ wrote:This can't work because parameters (I bet you mean constructor arguments here) can be variadic.KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.
Oct 25 2008
KennyTM~ wrote:Yigal Chripun wrote:I did mean the constructor arguments. The syntax itself is less important here, I was more talking about the concept of Allocators. like the ones in STL, for example. regarding the syntax: a few possibilities that come to mind: a) new!(Allocator)(args).. b) Allocator is just a regular parameter which you can add to your args list. now the c-tor need some machinery to handle the allocator. I'd say something like: a c-tor does two things, gets memory and puts stuff into that memory. so the first thing a c-tor does is automatically calls a default Allocator for the type to get memory, *unless* you call one explicitly yourself. it's similar to the way a c-tor has an implicit super() call if you don't call that yourself only this probably will need additional machinery to work. other ideas how to approach this?KennyTM~ wrote:This can't work because parameters (I bet you mean constructor arguments here) can be variadic.KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.
Oct 25 2008
Yigal Chripun wrote:KennyTM~ wrote:Then Allocator must be known in compile time? Though also in STL.Yigal Chripun wrote:I did mean the constructor arguments. The syntax itself is less important here, I was more talking about the concept of Allocators. like the ones in STL, for example. regarding the syntax: a few possibilities that come to mind: a) new!(Allocator)(args)..KennyTM~ wrote:This can't work because parameters (I bet you mean constructor arguments here) can be variadic.KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.b) Allocator is just a regular parameter which you can add to your args list. now the c-tor need some machinery to handle the allocator. I'd say something like: a c-tor does two things, gets memory and puts stuff into that memory. so the first thing a c-tor does is automatically calls a default Allocator for the type to get memory, *unless* you call one explicitly yourself. it's similar to the way a c-tor has an implicit super() call if you don't call that yourself only this probably will need additional machinery to work.Yes. Although the problem right now is syntactical. :(other ideas how to approach this?Use the semicolon: Class.new(parameters; allocator params);
Oct 25 2008
KennyTM~ wrote:Yigal Chripun wrote:if there's an allocator object, you don't need the above. just pass the extra params to the alloc object itself and not the C-tor. i.e: Class.new(params, Allocator(params)); extended example: SharedMemoryAllocator shmAlloc(params); auto a = ClassA.new(params, shmAlloc); auto b = ClassB.new(params, shmAlloc); auto c = StructA.new(params, shmAlloc); auto d = ClassC.new(params); // default Class Allocator (on heap) auto e = Struct.new(params); // default Struct Allocator (on stack) auto d = ClassC.new(params, StackAlloc); // on stack auto e = Struct.new(params, GCAlloc); // on heap something like that will require the compiler/runtime to recognize the allocator interface as special I think...KennyTM~ wrote:Then Allocator must be known in compile time? Though also in STL.Yigal Chripun wrote:I did mean the constructor arguments. The syntax itself is less important here, I was more talking about the concept of Allocators. like the ones in STL, for example. regarding the syntax: a few possibilities that come to mind: a) new!(Allocator)(args)..KennyTM~ wrote:This can't work because parameters (I bet you mean constructor arguments here) can be variadic.KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.b) Allocator is just a regular parameter which you can add to your args list. now the c-tor need some machinery to handle the allocator. I'd say something like: a c-tor does two things, gets memory and puts stuff into that memory. so the first thing a c-tor does is automatically calls a default Allocator for the type to get memory, *unless* you call one explicitly yourself. it's similar to the way a c-tor has an implicit super() call if you don't call that yourself only this probably will need additional machinery to work.Yes. Although the problem right now is syntactical. :(other ideas how to approach this?Use the semicolon: Class.new(parameters; allocator params);
Oct 25 2008
Yigal Chripun wrote:KennyTM~ wrote:What if the constructor may take the allocator object as its argument? class X { string t; this(string x, Allocator alc = Allocator.init) { t = x ~ alc.toString(); // why not? } } SharedMemoryAllocator shmAlloc(alloc_params); auto x = X.new("abc", shmAlloc); // what I'm calling? The semi-colon version disambiguates this situation.Yigal Chripun wrote:if there's an allocator object, you don't need the above. just pass the extra params to the alloc object itself and not the C-tor. i.e: Class.new(params, Allocator(params)); extended example: SharedMemoryAllocator shmAlloc(params); auto a = ClassA.new(params, shmAlloc); auto b = ClassB.new(params, shmAlloc); auto c = StructA.new(params, shmAlloc); auto d = ClassC.new(params); // default Class Allocator (on heap) auto e = Struct.new(params); // default Struct Allocator (on stack) auto d = ClassC.new(params, StackAlloc); // on stack auto e = Struct.new(params, GCAlloc); // on heap something like that will require the compiler/runtime to recognize the allocator interface as special I think...KennyTM~ wrote:Then Allocator must be known in compile time? Though also in STL.Yigal Chripun wrote:I did mean the constructor arguments. The syntax itself is less important here, I was more talking about the concept of Allocators. like the ones in STL, for example. regarding the syntax: a few possibilities that come to mind: a) new!(Allocator)(args)..KennyTM~ wrote:This can't work because parameters (I bet you mean constructor arguments here) can be variadic.KennyTM~ wrote:maybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.Bill Baxter wrote:or do it like this: auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.On Sat, Oct 25, 2008 at 2:04 AM, KennyTM~ <kennytm gmail.com> wrote:I see. But with the your new(...) syntax this can't be done because it is ambiguous with void* stack = allocate(); auto C = Class.new(stack)(); The placement new syntax should use some other syntax.Right, that's why both Benji and I proposed making them *context* keywords. Just like "Windows" is a keyword only in the context of extern( ). This would make heap and stack keywords only in the context of new( ).auto a = Class(); // heap (default) auto a = Struct(); // stack (default) auto a = Class.new(stack)(); // stack auto a = Struct.new(stack)(); // stack auto a = Class.new(heap)(); // heap auto a = Struct.new(heap)(); // heap void *addr; auto a = Class.new(addr)(); // placement auto a = Struct.new(addr)(); // placementI strongly *oppose* using stack and heap as keywords because there are also (partly irrelevant) data structures called stack and heap, even though according to the guideline these class/structs should be named Stack and Heap.b) Allocator is just a regular parameter which you can add to your args list. now the c-tor need some machinery to handle the allocator. I'd say something like: a c-tor does two things, gets memory and puts stuff into that memory. so the first thing a c-tor does is automatically calls a default Allocator for the type to get memory, *unless* you call one explicitly yourself. it's similar to the way a c-tor has an implicit super() call if you don't call that yourself only this probably will need additional machinery to work.Yes. Although the problem right now is syntactical. :(other ideas how to approach this?Use the semicolon: Class.new(parameters; allocator params);
Oct 25 2008
On Sat, Oct 25, 2008 at 11:03 PM, KennyTM~ <kennytm gmail.com> wrote:Yeh, I was thinking that was a possibility too, if .new(heap,a) .new(stack,a) and .new(a) weren't sufficiently distinct. I was thinking to call it .new(place,a), though. But same idea.auto C = Class.new(placement, addr, etc)(); //--------------------^ use this to specify it is a placement new.You could fix that by putting the allocator first, or attach params to the allocator auto C4 = Class.new(MyPlacementNewAllocator(parameters)) The bigger concern to me is that StackAllocator can't be just a regular allocator. The compiler would have to recognize that StackAllocator was being used and reserve the appropriate space on the stack, and then pass that stack address to the StackAllocator somehow. It's not impossible but it sounds messy from the implementation perspective. And I find it kind of jarring that the three modes look similar, but one is actually invoking deep compiler magic while the other two are just regular Joes. --bbmaybe just add the concept of allocators. auto C1 = Class.new(parameters/*, Allocator = GC.DefaultAllocator */); auto C2 = Class.new(parameters, HeapAllocator); // on heap auto C3 = Class.new(parameters, StackAllocator); // on stack auto C4 = Class.new(parameters, MyPlacementNewAllocator); etc.. initial Allocator hierarchy could be part of the run-time, and could be user extended to allow for placement new.This can't work because parameters (I bet you mean constructor arguments here) can be variadic.
Oct 25 2008
== Quote from Bill Baxter (wbaxter gmail.com)'s articleIt kills static opCall for classes, but who cares.Actually, I sometimes use static opCall to encapsulate the creation of temp variables that I might want to recycle for performance reasons in some cases, though more likely with a struct than with a class. Example: SomeType foo() { auto temp = new SomeType[someNumber]; doStuff; return someStuff; } would become: struct foo { SomeType[] temp; static opCall() { //Creates a foo, simulates a regular function call. //Good for when I don't care about recycling temp storage. foo f; return f.doStuff; } SomeType doStuff() { temp.length = someNumber; //Only allocates first time. doStuff; return temp; } } This way, I can either use it the clean, easy way via the static opCall simulating a regular function call, or the efficient way by making an explicit instance of the struct, and doStuff() in a loop.
Oct 23 2008
On Fri, Oct 24, 2008 at 5:55 AM, dsimcha <dsimcha yahoo.com> wrote:== Quote from Bill Baxter (wbaxter gmail.com)'s articleThere are definitely uses for static opCall, but it's all just for cuteness' sake. There's no reason you can't use a regular static method instead. Like temp.length = someNumber.tmp; // static method call, only allocates first time --bbIt kills static opCall for classes, but who cares.Actually, I sometimes use static opCall to encapsulate the creation of temp variables that I might want to recycle for performance reasons in some cases, though more likely with a struct than with a class. Example: SomeType foo() { auto temp = new SomeType[someNumber]; doStuff; return someStuff; } would become: struct foo { SomeType[] temp; static opCall() { //Creates a foo, simulates a regular function call. //Good for when I don't care about recycling temp storage. foo f; return f.doStuff; } SomeType doStuff() { temp.length = someNumber; //Only allocates first time. doStuff; return temp; } } This way, I can either use it the clean, easy way via the static opCall simulating a regular function call, or the efficient way by making an explicit instance of the struct, and doStuff() in a loop.
Oct 23 2008
On Thu, Oct 23, 2008 at 8:47 PM, Yigal Chripun <yigal100 gmail.com> wrote:Bill Baxter wrote:Hmm, I didn't realize D had a placement new. But clearly it does and more -- you can pass args to new to control the allocator. http://www.digitalmars.com/d/2.0/class.html look for "Class Allocators". also http://www.digitalmars.com/d/2.0/memory.html#newdelete So simply saying make it Obj.new(args) won't cut it. You need to be able to do something like Obj.new(newargs)(constructorargs) also. --bbOn Thu, Oct 23, 2008 at 6:32 PM, bearophile <bearophileHUGS lycos.com> wrote:Andrei already mentioned that he wants to get read of new/delete IIRC. I like Ruby's way of making it regular methods. something like: obj.new(..) and obj.delete() but, how do you specify stack vs heap allocation? something like: auto a = new S(); //on heap auto b = S(); //on stack also, what about placement new?In Python to create new instances of a class you use the normal function call syntax, this allows you to use them as factory functions: class C: def __init__(self, id): self.id = id def __repr__(self): return "<%s>" % self.id seq = map(C, [1, -5, 10, 3]) That creates an array (list) of four objects. In D with a map() you can do something similar: import d.all; import std.string: format; class C { int id; this(int id) { this.id = id; } string toString() { return format("<%s>", this.id); } static C opCall(int id) { return new C(id); } } void main() { auto seq = map((int id){return new C(id);}, [1, -5, 10, 3]); putr(seq); } You can use the opCall method in a more direct way: auto seq2 = map(&(C.opCall), [1, -5, 10, 3]); putr(seq2); But probably even better is to replace the current new syntax with a class method that creates the instances (I think the Ruby language has such syntax): auto seq3 = map(C.new, [1, -5, 10, 3]); putr(seq3);That would be map(&(C.new), [1,-5,10,3]); wouldn't it?With that normal code like: new Foo(10, 20) becomes: Foo.new(10, 20) Not a big change but allows a more functional style of coding.I like it. Can we get rid of delete's specialness too? Maybe just delete(anInstance); Make it like a normal function too. Enabling things like map(&delete, [obj1, obj2, obj3]) --bb
Oct 23 2008