View mode: basic / threaded / horizontal-split · Log in · Help
December 11, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Burton Radons wrote:
> 
>> Here's the difference:
>>
>>     struct S
>>     {
>>         this (int x)
>>         {
>>             w = calculate_something (x);
>>         }
>>
>>         this (int x, int y)
>>         {
>>             this (x);
>>             z = calculate (y);
>>         }
>>     }
> 
> 
> struct S
> {
>     static S opCall(int x)
>     {
>     S result;
>     result.w = calculate_something(x);
>     return result;
>     }
> 
>     static S opCall(int x, int y)
>     {
>     auto result = S(x);
>     result.z = calculate(y);
>     return result;
>     }
> }
> 
> It's 3 more lines of code. The two styles almost completely overlap, and 
> since the latter is already in use, adding ctors just seems redundant.

OK here are the things that make me want constructors instead of static 
opCall:

It takes a lot longer to type.  You say only 3 more lines, but in that 
example 9 lines of constructor code becomes 12 lines of opCall code. 
The resulting code that is specific to these features is 25% fluff, and 
that includes the trivial curly braces.  Character wise it is worse.

The typing doesn't bug me as much as this though: what if the struct's 
name changes?  And what if the opCall is heavily overloaded when the 
name changes?  It's more unneeded code refactoring.  That is one reason 
D constructors are so cool, and it kinda sucks that structs don't have 
that too.

Also, static opCall is almost always used in the same way as a 
constructor.  I'd expect them to have the same syntax, but they don't. 
I think this, and some of the above reaons, result in the workaround 
perception - everyone expects the smooth 'this' syntax, but get static 
opCall instead.

Now I read that you would like to keep the semantic differences intact 
because they are useful.  Forcing the possibility of a bitwise copy of 
the struct before it is unleashed will apparently allow for cool stuff. 
 I don't think it's too unreasonable to have the 'this' identifier be a 
value rather than a reference in a struct constructor.  Thus you have a 
function that implicitly creates a blank instance of the struct, then 
allows the programmer to modify it via 'this', and implicitly returns 
the 'this' struct as static opCall would.
December 11, 2006
Re: DMD 0.177 release
Chris Miller wrote:
> 
> char* p = new char[32];
> 
> Error: cannot implicitly convert expression (new char[](32)) of type 
> char[] to char*
> 
> Should this be a special case? Currently it needs  (new char[32]).ptr

Well, the problem is that since this change, char[] is not the same 
thing as char*; IMO, this is a good thing.  You really should have to 
jump through an extra hoop to get there, because they're not the same. 
It's no different than a cast, if it is a little harder to type.

-- 
- EricAnderton at yahoo
December 11, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> More ABI changes, and implicit [] => * no longer allowed.
> 
> http://www.digitalmars.com/d/changelog.html
> 
> http://ftp.digitalmars.com/dmd.175.zip

Walter, this is a great update.  Especially the removal of the implicit 
cast for array pointers.

But I'd like to echo the other comments in this thread regarding 
structs.  IMO, we're not there yet.  I think folks are looking for a 
solution that does this:

- A ctor like syntax for creating a new struct
- No more forced copy of the entire struct on creation
- Something that is disambiguated from static opCall
- Ctors that are as clear to read as this() in classes and modules.

Again, thanks for the solid push to 1.0 this month.  I'm sure we haven't 
seen anything yet.

-- 
- EricAnderton at yahoo
December 11, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Chris Miller wrote:
>> On Sat, 09 Dec 2006 13:59:24 -0500, Walter Bright 
>> <newshound@digitalmars.com> wrote:
>> 
>>> Chris Miller wrote:
>>>> Allow static opAssign to return an instance of the class that will 
>>>> be assigned to the lvalue:
>>> 
>>> This wasn't done because there are several use cases where you 
>>> wouldn't want to erase all previous contents of the struct being 
>>> assigned to.
>> 
>> But if it's optional it's up to the struct writer to use void as the 
>> return or not.
> 
> I don't think that'll work. He'll wind up being forced to set all the 
> fields.

Doesn't follow - there might not be any to set other than those that are
an inherent part of the assignment operation.

For example, consider an immutable big integer class.  One might want

    Int x;
    ...
    x = 42;

as syntactic sugar for

    x = new Int(42);

Stewart.
December 11, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Tom S wrote:
>> The Foo instance returned from static opCall is copied, thus the 'ctor 
>> hack' doesn't have real access to the object it's constructing, not to 
>> mention the overhead of copying the struct to another place on stack...
> 
> 
> It's time to put the recurring efficiency argument to bed. Consider this 
> D code:
[...]

In many cases, it may be vary good. However consider the case where 
there is more than one return statement using different variables. You 
now need a much better optimizer to get this optimized down to "almost 
nothing". Furthermore, it doesn't reflect what is actually being done.

struct S
{
	static S err;
	int k, l;

	static S opCall(int i, int j)
	{
		S ret;
		ret.k=i;
		ret.l=j;

		if(ret.test)
			return ret;
		else
			ret err;
	}

	bool test(){...}
}


With constructors, it is not only simpler code, but looks like what is 
happening.

struct S
{
	static S err;
	int k, l;

	this(int i, int j)
	{
		k=i;
		l=j;

		if(!ret.test) this = err;
	}

	bool test(){...}
}
December 11, 2006
Re: DMD 0.177 release
Brad Roberts wrote:
> 
> Since the desired behavior is construction, let's stop kidding ourselves 
> and actually give structs both the behavior and the syntax of 
> construction, please?  And while you're in there.. how about destruction 
> and RAII?

What ever happened to structs as aggregates?  I thought this was their 
entire purpose for being in D.  Adding ctors makes sense because it 
merely simplifies initialization, but adding dtors, copy semantics, and 
opAssign all seem bent on making structs into something they're not. 
After all, isn't that why we have classes?  In fact, many of the 
instances where I was inclined to use structs simply to avoid the GC 
evaporated when stack construction of classes was added a few releases 
ago.  Aside from the addition of a ctor, I'm quite happy to leave 
structs exactly as they were before 177.  That said, I suppose I can 
appreciate the desire to give classes opAssign (even though it's 
somewhat weird), and perhaps the operator was added to structs simply 
for the sake of consistency.


Sean
December 11, 2006
Re: DMD 0.177 release
Sean Kelly wrote:
> Brad Roberts wrote:
> 
>>
>> Since the desired behavior is construction, let's stop kidding 
>> ourselves and actually give structs both the behavior and the syntax 
>> of construction, please?  And while you're in there.. how about 
>> destruction and RAII?
> 
> 
> What ever happened to structs as aggregates?  I thought this was their 
> entire purpose for being in D.  Adding ctors makes sense because it 
> merely simplifies initialization, but adding dtors, copy semantics, and 
> opAssign all seem bent on making structs into something they're not. 
> After all, isn't that why we have classes?  In fact, many of the 
> instances where I was inclined to use structs simply to avoid the GC 
> evaporated when stack construction of classes was added a few releases 
> ago.  Aside from the addition of a ctor, I'm quite happy to leave 
> structs exactly as they were before 177.  That said, I suppose I can 
> appreciate the desire to give classes opAssign (even though it's 
> somewhat weird), and perhaps the operator was added to structs simply 
> for the sake of consistency.

Classes are different from structs in two essential ways:

1. Polymorphism
2. Referential semantics

The two are actually interdependent, as you can't have polymorphism
comfortably unless you have reference semantics.

That's the important distinction. Other than that, it's good that they
share a number of valuable properties. Take private state for example.
structs as sheer unchecked aggregates would provide too little value to
be useful. Most of the time, aggregating some state together (date,
time, etc.) comes together with some desirable invariant that the 
aggregate should hold, meaning that not all possible bit patterns of the 
aggregate can be meaningful. So it's useful that struct has private 
state. Consequently, they should have member functions (setters, 
getters) and the such. They also should have constructors so they can 
put themselves in a meaningful initial state, and should have opAssign 
so they allow controlled overwriting of their state. (It's an accident 
that opAssign from the same type has not been implemented yet; it can be 
safely allowed.)

On the other hand, intercepting _duplication_ of structs naively would 
be a major breach in the object model, because it would frontally 
collide with (2) above: structs are values and the compiler can move and 
copy structs around discretionary using bitwise copying. That's why D
currently does not allow interception of copy construction and 
destruction. It might in the future, but in a way that does not clash 
with the object model. (That is doable.)

So my point was, as attractive the simple mantra "structs should be
aggregates" is, it turns out it's not that useful. So it's great that D
supports efficient and safe user-defined values.


Andrei
December 11, 2006
Re: DMD 0.177 release
Andrei Alexandrescu (See Website For Email) wrote:
> Sean Kelly wrote:
>> Brad Roberts wrote:
>>
>>>
>>> Since the desired behavior is construction, let's stop kidding 
>>> ourselves and actually give structs both the behavior and the syntax 
>>> of construction, please?  And while you're in there.. how about 
>>> destruction and RAII?
>>
>>
>> What ever happened to structs as aggregates?  I thought this was their 
>> entire purpose for being in D.  Adding ctors makes sense because it 
>> merely simplifies initialization, but adding dtors, copy semantics, 
>> and opAssign all seem bent on making structs into something they're 
>> not. After all, isn't that why we have classes?  In fact, many of the 
>> instances where I was inclined to use structs simply to avoid the GC 
>> evaporated when stack construction of classes was added a few releases 
>> ago.  Aside from the addition of a ctor, I'm quite happy to leave 
>> structs exactly as they were before 177.  That said, I suppose I can 
>> appreciate the desire to give classes opAssign (even though it's 
>> somewhat weird), and perhaps the operator was added to structs simply 
>> for the sake of consistency.
> 
> Classes are different from structs in two essential ways:
> 
> 1. Polymorphism
> 2. Referential semantics
> 
> The two are actually interdependent, as you can't have polymorphism
> comfortably unless you have reference semantics.
> 
> That's the important distinction. Other than that, it's good that they
> share a number of valuable properties. Take private state for example.
> structs as sheer unchecked aggregates would provide too little value to
> be useful. Most of the time, aggregating some state together (date,
> time, etc.) comes together with some desirable invariant that the 
> aggregate should hold, meaning that not all possible bit patterns of the 
> aggregate can be meaningful. So it's useful that struct has private 
> state. Consequently, they should have member functions (setters, 
> getters) and the such. They also should have constructors so they can 
> put themselves in a meaningful initial state, and should have opAssign 
> so they allow controlled overwriting of their state. (It's an accident 
> that opAssign from the same type has not been implemented yet; it can be 
> safely allowed.)
> 

"allow controlled overwriting of their state" -> Would that be for the 
case where the struct's private state (aka abstract state) is not just 
the bit pattern value of the struct, but also the contents of 
pointer/reference members?

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
December 11, 2006
Re: DMD 0.177 release
Bruno Medeiros wrote:
> "allow controlled overwriting of their state" -> Would that be for the 
> case where the struct's private state (aka abstract state) is not just 
> the bit pattern value of the struct, but also the contents of 
> pointer/reference members?

That too. The canonical example is simpler - reject invalid attempts at 
setting state. Consider:

struct BoundedInt(int min, int max) {
  ...
}

alias BoundedInt!(0, 100) Percent;

Percent soFar = 0;
...
soFar = bytesCopied * 100 / bytesToCopy;

Upon assignment, the bounded int structure should do a runtime check to 
make sure it is being set to a number within bounds.


Andrei
December 11, 2006
Re: DMD 0.177 release
On Mon, 11 Dec 2006 10:50:41 -0800, Sean Kelly <sean@f4.ca> wrote:

> Brad Roberts wrote:
>>  Since the desired behavior is construction, let's stop kidding  
>> ourselves and actually give structs both the behavior and the syntax of  
>> construction, please?  And while you're in there.. how about  
>> destruction and RAII?
>
> What ever happened to structs as aggregates?  I thought this was their  
> entire purpose for being in D.  Adding ctors makes sense because it  
> merely simplifies initialization, but adding dtors, copy semantics, and  
> opAssign all seem bent on making structs into something they're not.  
> After all, isn't that why we have classes?  In fact, many of the  
> instances where I was inclined to use structs simply to avoid the GC  
> evaporated when stack construction of classes was added a few releases  
> ago.  Aside from the addition of a ctor, I'm quite happy to leave  
> structs exactly as they were before 177.  That said, I suppose I can  
> appreciate the desire to give classes opAssign (even though it's  
> somewhat weird), and perhaps the operator was added to structs simply  
> for the sake of consistency.
>
>
> Sean


I used to be convinced that struct's needed constructors; but now I see  
that there is a steam-roll effect as the demand for one class-like  
attribute is proposed: suddenly people want more class-related  
functionality or people argue that there is a basis for additional  
features for the sake of consistancy.  Then the redesign of structs starts  
taking on the appearance of a reegineered, specialized class -- something  
of a "context switch" too since classes use reference semantics.  Perhaps  
we should be careful about hurtling too far in the direction of C++?

From the perspective of setting initial state, classes in the OOP context  
use constructors to do that.  Structs were never intended to have OOP like  
syntax (or so it seems to me).  Why can't structs just use an initializer  
like constants or statics?  I notice that Walter has added the struct  
initialization using S(x) syntax.  I think it is somewhat strange, but I  
suppose that was designed to be an alternative to constructor  
initialization?   What happened to something like a struct literal  
intializer (which only works for static structs and constant values)?  Why  
can't such initialization be extended to local structs?

...
struct S
{
   int i;
   bool b;
}

static S t = { 5, true };  // must be "static" or initialization won't work
...

The above only works for static Structs.  But that kind of initialization  
seems to be more consistant with the imperitive style of structs verses  
the OOP style of classes (if only non-statics could be initialized too,  
that is). When all is said and done, this is just like doing the same as  
S( 5, 2 ) since 0.177.

But I guess as soon as we start adding "methods" to the struct that are  
responsible for changing state in the struct, a whole new set of  
principles comes to work.  Adding constructor funtionality via "this()" is  
only one way to fix it.  opCall, the current way, is a rather ugly  
default.  If it is important to keep structs distinct from classes, then  
structs need to adopt a alternate way of doing initialization (but please  
not opCall).  I don't think "this()" really is the optimal way, though  
perhaps the most familiar due to the influence of classes.  I think there  
should remain a strong distinction between class and struct.

If, nevertheless, Walter decides to implement a "this" constructor for  
struct, I really hope he doesn't feel the need to go with a destructor and  
more class-like functionality as well.

Ironically, I feel more sympathetic to what appears to be Walter's opinion  
on the matter this time around. :D

-JJR
4 5 6 7 8 9 10 11 12
Top | Discussion index | About this forum | D home