September 22, 2014
On Sunday, 21 September 2014 at 23:00:09 UTC, ketmar via Digitalmars-d wrote:
> On Sun, 21 Sep 2014 22:07:21 +0000
> Ola Fosheim Grostad via Digitalmars-d <digitalmars-d@puremagic.com>
> wrote:
>
>> I am waiting for a patch...
> i believe that we should revive 'typedef' keyword, but i'm not fully
> convinced yet. so i'll wait a little more. but you guessed it right,
> i'm thinking about another patch. ;-)

Why not introduce a std.typecons.Newtype(T) with the desired semantics in addition to Typedef(T)?

Btw, there is an argument to be made _for_ the current Typedef: If it generates an unpredictable cookie every time it is used (and I would count __LINE__ as one, as it can change easily), it's very hard to keep binary compatibility. Maybe taking only __MODULE__ in consideration would be a good compromise, because it at least avoids accidental cross module hijacking.
September 22, 2014
On Sunday, 21 September 2014 at 18:09:26 UTC, Andrei Alexandrescu wrote:
> On 9/21/14, 8:29 AM, ketmar via Digitalmars-d wrote:
>> On Sun, 21 Sep 2014 08:15:29 -0700
>> Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com>
>> wrote:
>>
>>> alias Int1 = Typedef!(int, "a.Int1");
>>> alias Int2 = Typedef!(int, "b.Int2");
>> ah, now that's cool. module system? wut? screw it, we have time-proven
>> manual prefixing!
>
> Use __MODULE__. -- Andrei


Yes, but you're advocating a hack. The original premise does seem to be correct: library Typedefs are fundamentally broken. The semantics of templates does not match what one expects from a typedef: ie, declaring a new, unique type.

If you have to pass __MODULE__ in, it's not really a library solution. The user code needs to pass in a nasty implementation detail in order to get a unique type.

And it does seem to me, that because it isn't possible to do a proper library typedef, you've attempted to redefine what a Typedef is supposed to do. And sure, it you remove the requirement to create a unique type, Typedef isn't broken. But then it isn't very useful, either. You can't, for example, use it to define the various Windows HANDLEs (HMENU, etc), which was one of the most successful use cases for D1's typedef.


Having said that, though, the success of 'alias this' does raise some interesting questions about how useful the concept of a typedef is. Certainly it's much less useful than when Typedef was created.

My feeling is that almost every time when you want to create a new type from an existing one, you actually want to restrict the operations which can be performed on it. (Eg if you have  typedef money = double; then money*money doesn't make much sense). For most typedefs I think you're better off with 'alias this'.
September 22, 2014
On Monday, 22 September 2014 at 09:39:29 UTC, Don wrote:
> My feeling is that almost every time when you want to create a new type from an existing one, you actually want to restrict the operations which can be performed on it. (Eg if you have  typedef money = double; then money*money doesn't make much sense). For most typedefs I think you're better off with 'alias this'.

`alias this` doesn't restrict what operations can be performed on the supertype.

struct Money
{
	this(double d)
	{
		amount = d;
	}
	
	double amount;
	alias amount this;
}

void main()
{
        //This doesn't compile without a constructor defined
        //that takes a double... I thought alias this took
        //care of that, but apparently not
	Money m = 2.0;
	Money n = m * m;
	assert(n == 4.0);
}
September 22, 2014
On 9/22/14, 2:39 AM, Don wrote:
> On Sunday, 21 September 2014 at 18:09:26 UTC, Andrei Alexandrescu wrote:
>> On 9/21/14, 8:29 AM, ketmar via Digitalmars-d wrote:
>>> On Sun, 21 Sep 2014 08:15:29 -0700
>>> Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com>
>>> wrote:
>>>
>>>> alias Int1 = Typedef!(int, "a.Int1");
>>>> alias Int2 = Typedef!(int, "b.Int2");
>>> ah, now that's cool. module system? wut? screw it, we have time-proven
>>> manual prefixing!
>>
>> Use __MODULE__. -- Andrei
>
>
> Yes, but you're advocating a hack.

Oh but I very much disagree.

> The original premise does seem to be
> correct: library Typedefs are fundamentally broken. The semantics of
> templates does not match what one expects from a typedef: ie, declaring
> a new, unique type.
>
> If you have to pass __MODULE__ in, it's not really a library solution.
> The user code needs to pass in a nasty implementation detail in order to
> get a unique type.

How many libraries did you use that came with no idioms for their usage?

> And it does seem to me, that because it isn't possible to do a proper
> library typedef, you've attempted to redefine what a Typedef is supposed
> to do. And sure, it you remove the requirement to create a unique type,
> Typedef isn't broken.

You're two paragraphs away from "library Typedefs are fundamentally broken". Now which one is it?

> But then it isn't very useful, either. You can't,
> for example, use it to define the various Windows HANDLEs (HMENU, etc),
> which was one of the most successful use cases for D1's typedef.

alias HMENU = Typedef!(void*, __MODULE__ ~ ".HMENU");

So please s/can't/can't the same exact way built-in typedef would have done it/.

> Having said that, though, the success of 'alias this' does raise some
> interesting questions about how useful the concept of a typedef is.
> Certainly it's much less useful than when Typedef was created.
>
> My feeling is that almost every time when you want to create a new type
> from an existing one, you actually want to restrict the operations which
> can be performed on it. (Eg if you have  typedef money = double; then
> money*money doesn't make much sense). For most typedefs I think you're
> better off with 'alias this'.

When control is needed, yah. I had some thoughts on adding policies to Typedef (convert to base type etc) but as it seems it's already unusable, I won't bring them up :o).


Andrei

September 22, 2014
On Saturday, 20 September 2014 at 04:52:58 UTC, Andrei Alexandrescu wrote:
>
> alias A = Typedef!float;
> alias B = Typedef!float;
>
> By basic language rules, A and B are identical. Making them magically distinct would be surprising...
>
Hold up.  See, "Making them magically distinct would be surprising" is really the sticking point for me because in my experience it rings false.

When I reach for a typedef, I expect these things to NOT be identical.  More to the point, I'm explicitly stating: "This thing is not like any other thing."  That's the fundamental reason any sort of typedef exists in my world.  That the idiomatic library Typedef doesn't actually give these semantics unless I do extra stuff? _That_ is surprising and inconvenient.  I'm personally having difficulty coming up with a situation where the current default behaviour is even useful.

You can make the argument that it's not that much of a burden.  And on a cursory read, sure, that makes enough sense.  But it's still there and still acts as positive punishment.  We tend to tout type safety as a major feature, which builds the expectation that getting it for the common case is _completely trivial_ and in-line with the pragmatic approach taken by the rest of the language.  Adding a gotcha like this makes it less likely to be used correctly.

And I think it needs to be stressed: No one is arguing that the current behaviour shouldn't be possible at all; just that it's an unusual special case that makes for a warty default.  If you want two distinctly-named types to hash the same, give them a common cookie and be on your merry way.  Meanwhile, the issues with e.g. Typedef in templates disappear because it makes introducing a unique type the trivial default.

Anecdotally, I was explaining how neat it is that D has library Typedef to an engineer on my team and he commented that he'd never expect a word like "alias" to be associated with defining a distinct type, suggesting its use here is a misfeature.  He also called the cookie parameter a wart (unprompted).

-Wyatt
September 22, 2014
On Monday, 22 September 2014 at 16:21:43 UTC, Wyatt wrote:
> On Saturday, 20 September 2014 at 04:52:58 UTC, Andrei Alexandrescu wrote:
>>
>> alias A = Typedef!float;
>> alias B = Typedef!float;
>>
>> By basic language rules, A and B are identical. Making them magically distinct would be surprising...
>>
> Hold up.  See, "Making them magically distinct would be surprising" is really the sticking point for me because in my experience it rings false.
>
> When I reach for a typedef, I expect these things to NOT be identical.  More to the point, I'm explicitly stating: "This thing is not like any other thing."  That's the fundamental reason any sort of typedef exists in my world.

IIRC, in the beginning, typedef was (assumed to be) just that. The problem was that the conversion rules lacked and, finally, nobody wrote them. Typedef itself became deprecated and merely a synonim for "alias".

Too bad, since the "strong typedef" was one of the things that dragged me into D from the C world...
September 22, 2014
On 9/22/14, 9:21 AM, Wyatt wrote:
> On Saturday, 20 September 2014 at 04:52:58 UTC, Andrei Alexandrescu wrote:
>>
>> alias A = Typedef!float;
>> alias B = Typedef!float;
>>
>> By basic language rules, A and B are identical. Making them magically
>> distinct would be surprising...
>>
> Hold up.  See, "Making them magically distinct would be surprising" is
> really the sticking point for me because in my experience it rings false.
>
> When I reach for a typedef, I expect these things to NOT be identical.
> More to the point, I'm explicitly stating: "This thing is not like any
> other thing."  That's the fundamental reason any sort of typedef exists
> in my world.  That the idiomatic library Typedef doesn't actually give
> these semantics unless I do extra stuff? _That_ is surprising and
> inconvenient. I'm personally having difficulty coming up with a
> situation where the current default behaviour is even useful.

I would agree with that. If I'd do it over again I'd probably make the string the second argument with no default.

> You can make the argument that it's not that much of a burden. And on a
> cursory read, sure, that makes enough sense.

It's a good argument. At some point some RTFM is necessary; I think it's reasonable to assume that whoever is in the market for using Typedef would spend a minute with the documentation.

> But it's still there and
> still acts as positive punishment.  We tend to tout type safety as a
> major feature, which builds the expectation that getting it for the
> common case is _completely trivial_ and in-line with the pragmatic
> approach taken by the rest of the language.  Adding a gotcha like this
> makes it less likely to be used correctly.

Type safety is not the problem here. I do agree that surprising behavior for those who don't RTFM is possible.

> And I think it needs to be stressed: No one is arguing that the current
> behaviour shouldn't be possible at all; just that it's an unusual
> special case that makes for a warty default.

I'd agree with that. (Again if I could do things over again there'd be no default for the cookie.) But my understanding is that there's quite a bit of blowing this out of proportion.

> If you want two
> distinctly-named types to hash the same, give them a common cookie and
> be on your merry way.  Meanwhile, the issues with e.g. Typedef in
> templates disappear because it makes introducing a unique type the
> trivial default.
>
> Anecdotally, I was explaining how neat it is that D has library Typedef
> to an engineer on my team and he commented that he'd never expect a word
> like "alias" to be associated with defining a distinct type, suggesting
> its use here is a misfeature.  He also called the cookie parameter a
> wart (unprompted).

It's an anecdote. How you explained matters matters a lot :o). I find the requirement for the cookie perfect.


Andrei

September 22, 2014
Andrei Alexandrescu:

> I find the requirement for the cookie perfect.

So far you're the only one, it seems. And you have admitted you have not tried to use them significantly in your code.

Bye,
bearophile
September 22, 2014
On Monday, 22 September 2014 at 17:21:50 UTC, Andrei Alexandrescu wrote:
> I find the requirement for the cookie perfect.

There is one thing I like about it and wish was available elsewhere: two modules can define the same type for interoperability without needing to import each other.

My simpledisplay.d and image.d modules both used to be standalone. Both defined struct Color {}. Identical layout. When I added optional integration, these two structs clashed.

The solution was to introduce module color, which held that struct. But now both modules require that import. Works fine but I think it would have been great if I could have kept the two separate definitions and just told the compiler it's ok, these two types are indeed identically compatible despite coming from independent modules.

kinda like pragma(mangle) but for types and preferably less hacky.


Another potential use of this concept would be separate interface and implementation files.


But that's all pretty different than the Typedef cookie. I'm just saying it because the concept of matching types in different modules IS something that I've wanted in the past.
September 22, 2014
On Mon, 22 Sep 2014 16:21:42 +0000
Wyatt via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> On Saturday, 20 September 2014 at 04:52:58 UTC, Andrei Alexandrescu wrote:
> >
> > alias A = Typedef!float;
> > alias B = Typedef!float;
> >
> > By basic language rules, A and B are identical. Making them magically distinct would be surprising...
> >
> Hold up.  See, "Making them magically distinct would be surprising" is really the sticking point for me because in my experience it rings false.

it's abusing 'alias' which makes it all a mess. if we look at the code above as 'idiomatic D code', then A and B should be similar. but if we looking at the code as 'hacky replacement for real typedef', A and B should not be similar.

seems that Andrei talking about 'idiomatic D' and we are talking about 'hacky typedef replacement'. that's why we can't settle the issue: we are both right! ;-)

and that's why we need 'typedef' revived, methinks.