Consistency, Templates, Constructors, and D3
Era Scarecrow
rtcvb32 at yahoo.com
Mon Aug 27 17:31:12 PDT 2012
On Monday, 27 August 2012 at 22:44:53 UTC, F i L wrote:
> Era Scarecrow wrote:
> C# structs are allocated on the stack when they can be. In
> certain cases (they're class fields, they're boxed, etc..)
> they're heap allocated.
So it will intentionally ignore 'new' and instead just call the
constructor and decide if it should be heap or not? Sounds both
helpful and harmful to me.
>> By looking at newFoo I'd say a class; But if like in C# I'm
>> sure you can't tell the difference (But C++ with the pointer
>> you can).
> the 'auto' keyword kind negates the 'Type*' distinction. My
> point here is that you pretty much have to look up the type
> definition (or a tooltip) to understand what you're working
> with when factory functions are involved.
I think that's why the naming should be something that sounds
easy to follow or follows a particular style. The following
should have no trouble figuring out even without seeing any
documentation. Mind you i'm throwing this out there without a
specific class in min.
File inputFile = File.createHandle("some file");
inputFile.load();
inputFile.close();
> The result is the same weather they're inside or outside a
> class, because, when used, all the coder sees is the function
> name to know about what it's returning.
Wrong. If you have it within a class, you know it comes FROM
that class. There may be multiple 'Records' depending on
different projects or having compatible types. In my own factory
function it polymorphs based on the input, so knowing the root
class makes sense to me.
> In D there is a difference between structs and classes beyond
> what's in C++. The 'new' keyword helps us understand what kind
> of object is being created, and I enjoy that. However, my
> argument is in favor of consistency because right now
> factory-functions, which _are_ used a lot, completely hide that
> distinction on top of being inconsistent with "normal" type
> construction.
>> And a postblits would end up being...? The extra 'this' makes
>> it look like an obvious typo or a minor headache.
>>
>> this this(this){} //postblitz?
>
> I'm sure this case has an easy solution. How about:
>
> struct Foo {
> this new() { ... } // constructor
> this() { ... } // postblit
> }
But now you're breaking consistency by not including a return
type. maybe 'this this()' but that looks like a mistake or typo.
If you're willing to use something without a return type, why not
leave it 'this(this)'? Or rename it all together? 'this
postblitz()'.
>> Only if you start getting creative can it begin to get
>> confusing;
>
> And I have to completely disagree with you here. Memory Pools
> are used everywhere in performance-critical code which needs a
> dynamic array of objects. At least half of all the "allocation"
> in game engines is done through factory functions that recycle
> objects.
Wasn't there already a way to specify (or going to be) what you
wanted to use an allocator? I thought i remember seeing an
example in TDPL.
> And for overload distinction (new vs load), which is an issue
> beyond Memory Pools and effects and even larger codebase. There
> needs to be a consistent way to distinguish (by name) a
> constructor that loads from a file, and one that creates the
> object "manually".
Isn't that more an API issue?
>> If we take your approach and suggestion, which one should the
>> compile assume?
>>
>> Something globalSomething;
>>
>> class Something {
>> this defaultConstructor();
>> this duplicate(); //or clone
>> this copyGlobalSomething();
>> this constructorWithDefault(int x = 100);
>> }
>>
>> By signature alone... Which one? They are all legal, they are
>> uniquely named, and they are all equal candidates. Order of
>> functions are irrelevant.
>
> It could work identically to how D functions today. A 'new()'
> constructor would be part of the root Object classes are
> derived of, and structs would have an implicit 'new()'
> constructor.
But new wouldn't be a constructor then would it? It would still
be based on allocating memory that's optionally different.
Constructor and allocation are two different steps; And for it to
seamlessly go from one to another defaults to having a set
default constructor. Let's assume...
class Object {
this new() {
//allocate
return defaultConstructor();
}
this defaultConstructor() {}
}
Now in order to make a constructor (and then destructor) you
either can:
A) overload or use 'defaultConstructor', which would be publicly
known
B) overload new to do allocation the same way and call a
different constructor and specifically add a destructor to make
sure it follows the same lines.
C) overload new to call the default allocator and then call a
different constructor
Now assuming you can make a different constructor by name, you
then have to be able to specify a destuctor the same way for
consistancy.
class CustomType {
this MyAwesomeConstuctor();
void MyAwesomeDestructor();
}
Same problem, how do you tell it ahead of time without
completely rewriting the rules? leaving it as 'this' and '~this'
are simple to remember and work with, and factory functions
should be used to do a bulk of work when you don't want the
basic/bare minimum.
> This could work in our favor, because instead of 'new' we could
> use 'alloc' (or something like that) while still encouraging
> 'new'. Which means structs could provide a parameter-less new()
> constructor:
> class Foo {
> float x;
> // no constructor
> }
>
> auto f = Foo.alloc();
> assert(f.x == float.nan);
>
> ---
>
> struct Point {
> float x, y;
> this new() { x = 0; y = 0; }
> this new(float x, float y) { ... }
> }
>
> auto a = Point.new();
> auto b = Point.new(1, 2);
> assert(a.x == 0.0f);
After reading a large chunk where Andrei spoke of the flaws of
C++'s classes and inheritance and potential problems having
stack/exact size allocated classes compared to leaving them on
the heap is coming to mind. This would undo all of that.
class Bar : Foo {
float y, z;
}
auto foo = Foo.alloc();
int isSafe;
foo = Bar.alloc(); //should implicity convert normally. But
stack?
assert(isSafe == int.init); //or was the next variables
overwritten??
In the cases where you don't overload anything would make the
classes safe, in which case they don't polymorph, in which case
you may as well use structs. Am I wrong on this?
More information about the Digitalmars-d
mailing list