On Aug 27, 2012, at 17:31, "Era Scarecrow" <rtcv...@yahoo.com> wrote:
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.
It works very similar to D's struct. If declared in a function they
are stack allocated. If declared in a class they are heap allocated.
Not sure what they do for global/static declarations. Probably
allocated in the data section.
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?