March 31, 2014
On Monday, 31 March 2014 at 03:25:11 UTC, Manu wrote:
> On 31 March 2014 12:21, Walter Bright <newshound2@digitalmars.com> wrote:
>
>> On 3/30/2014 6:33 PM, Manu wrote:
>>
>>> This is an interesting idea. Something I never thought of, and I think I
>>> like it!
>>>
>>
>> Frankly, I don't know why you use classes at all. Just use structs.
>>
>
> Reference types are very useful. Most programmers are familiar with this
> workflow, and it's a convenient way of modelling lots of problems.
>
> I do find myself using a lot more struct's in D though, but that doesn't
> void the traditional approach. And I also maintain that these things are
> important particularly as a bridge for new D users.
> I also feel quite dirty using pointers in D where there is a dedicated
> reference type available. I don't want * and & to appear everywhere in my D
> code.

Again and again I find myself reluctantly turning a struct into a class simply to get the reference semantics. Sure I could find work arounds and use * and & etc., but it just does not feel right, because hacks should only be the last resort, not something that is all over the place in your code. As has been mentioned earlier in this thread, these things often come back and bite you and all of a sudden it doesn't seem "so clever" anymore. On the other hand, I don't think that we should change the language, because of random annoyances that might partly be down to our design decisions taken earlier in the code.
March 31, 2014
On Monday, 31 March 2014 at 09:32:20 UTC, Manu wrote:
> Most computers aren't 64bit though.

This isn't accurate.

The most popular Steam OS is Windows 7, 64bit. http://store.steampowered.com/hwsurvey/

Steam usage data shows the the overwhelming majority of Windows 8 installs are 64-bit, so newer Windows installs are 64-bit almost as a rule.

Old Microsoft posts show a surge in 64-bit installs. http://blogs.windows.com/windows/b/bloggingwindows/archive/2010/07/08/64-bit-momentum-surges-with-windows-7.aspx

Modern Microsoft and Sony consoles use 64-bit processors.

Smartphones and tablets are a notable exception, probably due to their lower memory requirements, but this won't last forever.

So I don't think it's fair to say "most computers aren't 64-bit." A good fair chunk of computers are.

March 31, 2014
On Monday, 31 March 2014 at 10:09:06 UTC, Artur Skawina wrote:
> No. This will bite you once you decide to overload Impl's ops, such as indexing and slicing.

I agree with you that this is a problem that can bite you, but there's a fairly easy solution: you shouldn't overload Impl's ops, nor should it have constructors, postblits, or destructors since they won't run when you expect them to either. Putting them on the outer struct works right and opens the door to new things like refcounting too.

But yeah, you're right that it would still compile if you did it wrong and that's potentially ugly.

>    struct RefType {
>       struct Impl {
>            // put all the stuff in here
>
>            @disable this(this);
>       }
>       Impl* impl;
>       ref Impl _get() @property { return *impl; }
>       alias _get this;
>
>       // add ctors and stuff that new the impl
>    }


not bad to my eyes,
March 31, 2014
On 03/31/14 15:16, Adam D. Ruppe wrote:
> On Monday, 31 March 2014 at 10:09:06 UTC, Artur Skawina wrote:
>> No. This will bite you once you decide to overload Impl's ops, such as indexing and slicing.
> 
> I agree with you that this is a problem that can bite you, but there's a fairly easy solution: you shouldn't overload Impl's ops, [...]

In real code that pseudo-ref implementation will not necessarily be anywhere near the
payload, and will often be factored out (it makes no sense to duplicate this
functionality in every type that needs it -- so it will be done as 'Ref!T').
Both value- and reference-semantics are very clear and intuitive, but an amalgamate
of reference semantics and pointer arithmetic is a mine waiting to explode; you only
need to forget that your not dealing with a "true reference" for a second. Which is
more likely to happen than not -- when you're dealing with a reference type 'C'
everywhere, it is natural to assume that 'C[10]' works -- that 'C[10]' expression
does not /look/ wrong, so the bug is very hard to spot.


> [...] nor should it have constructors, postblits, or destructors since they won't run when you expect them to either. Putting them on the outer struct works right and opens the door to new things like refcounting too.

Been there, done that. Don't try at home. (Immediately ran into several language
and compiler issues, after working around quite a few ended up with code that
caused data corruption. A compiler that crashes on a block of code, but
accepts that very same block copy&pasted twice, is not fun to deal with... Maybe
things improved in the last two years or so since I did that, but I doubt it.)


>>    struct RefType {
>>       struct Impl {
>>            // put all the stuff in here
>>
>>            @disable this(this);
>>       }
>>       Impl* impl;
>>       ref Impl _get() @property { return *impl; }
>>       alias _get this;
>>
>>       // add ctors and stuff that new the impl
>>    }
> 
> 
> not bad to my eyes,

I think this is as good as it gets, in a language without proper refs. Still you have ABI issues (passing a struct around can be hadled differently from the bare-pointer case on some platforms) and the 'Ref!T' syntax is less than ideal.

artur
March 31, 2014
On 3/31/2014 4:44 AM, w0rp wrote:
> So I don't think it's fair to say "most computers aren't 64-bit." A good fair
> chunk of computers are.

At least as far as desktops go, 32 bits is dead.

March 31, 2014
On 3/31/2014 3:09 AM, Artur Skawina wrote:
> This is a catastrophic failure mode. Op overloads may be added to the pseudo-C
> after it's already written and working, and then a) the bug might go unnoticed,
> and b) fixing it requires API changes. See also my other reply.

Manu brought up the same issue, see my reply to him.

April 01, 2014
On 31 March 2014 18:16, Walter Bright <newshound2@digitalmars.com> wrote:

> On 3/31/2014 12:51 AM, Manu wrote:
>
>> Now it's deceptive that it's a pointer, and the pointer semantics are not
>> suppressed. It might be surprising to find that a type that doesn't look
>> like a
>> pointer behaves like a pointer.
>> You lose access to the operators, indexing/slicing etc, etc.
>> I don't see how this is a reasonable comparison to 'class' as a reference
>> type
>> by definition.
>>
>
> Of course it's reasonable - not many classes overload operators.
>

Is there a way to disable indexed dereferencing? Slicing?

The point is, there are numerous solutions available, you aren't stuck with
> one solution for every problem.
>

I just wouldn't go so far as to call these alternatives 'solution's. A
pointer is a pointer.
Calling it a reference type is a stretch. While it can be indexed, sliced,
and operators don't work, I don't think this is a compelling solution in
very many contexts, and certainly not a general solution.

And, you can use 'alias this' as Adam showed to create a type with fully
> customized behavior - you don't have to change the language to prove your ideas.
>

I haven't made any suggestion to change the language, I just said that adam's idea (well, not necessarily his idea, it seems to be an established pattern) is a rather elaborate hack; in many cases the boilerplate exceeds the volume of the useful code. The whole pointer-to-Impl + getter property + alias this + etc pattern is quite a lot of boilerplate.

It's a really common pattern, it's obviously very useful, but it's
surprising to me that people think that it's like, 'cool'.
I get why it's done, and it's cool that D can do this (I use it a lot in my
code), but I don't feel it's particularly elegant.


April 01, 2014
On 31 March 2014 21:44, w0rp <devw0rp@gmail.com> wrote:

> On Monday, 31 March 2014 at 09:32:20 UTC, Manu wrote:
>
>> Most computers aren't 64bit though.
>>
>
> This isn't accurate.
>
> The most popular Steam OS is Windows 7, 64bit. http://store.steampowered.com/hwsurvey/
>
> Steam usage data shows the the overwhelming majority of Windows 8 installs are 64-bit, so newer Windows installs are 64-bit almost as a rule.
>
> Old Microsoft posts show a surge in 64-bit installs. http://blogs.windows.com/windows/b/bloggingwindows/ archive/2010/07/08/64-bit-momentum-surges-with-windows-7.aspx


Desktop computers are a relatively small fraction of computers in the world today, and losing market share rapidly.


Modern Microsoft and Sony consoles use 64-bit processors.
>

Finally, we have plenty of ram! Huzzah! :)


Smartphones and tablets are a notable exception, probably due to their
> lower memory requirements, but this won't last forever.
>
> So I don't think it's fair to say "most computers aren't 64-bit." A good fair chunk of computers are.
>

It's completely fair; it's fact that 'most' (literally) computers today are
32 bit, and the current trend is away from 64 bit, although that should
change as mobile adopts 64 bit too.
I suspect it'll be quite a while yet before developers can forget about 32
bit devices. I think there's only one 64 bit mobile device on the market so
far?

The point is, it's impossible to bank on pointers being either 32 or 64 bit. This leads to #ifdef's at the top of classes in my experience. D is not exempt.


April 01, 2014
On 3/31/2014 10:02 PM, Manu wrote:
> It's a really common pattern, it's obviously very useful, but it's surprising to
> me that people think that it's like, 'cool'.
> I get why it's done, and it's cool that D can do this (I use it a lot in my
> code), but I don't feel it's particularly elegant.

'alias this' is inelegant (sorry Andrei) but it was designed for precisely this purpose - being able to use a struct to wrap any other type, and forward to and override behaviors of that type. Nobody has found a better way.

Fortunately, the inelegance can be encapsulated within that type, and the user of the type need not be even aware of it.

Remember my halffloat implementation? It relied on 'alias this' to work. Just try doing that in C++ <g>.
April 01, 2014
On 1 April 2014 15:53, Walter Bright <newshound2@digitalmars.com> wrote:

> On 3/31/2014 10:02 PM, Manu wrote:
>
>> It's a really common pattern, it's obviously very useful, but it's
>> surprising to
>> me that people think that it's like, 'cool'.
>> I get why it's done, and it's cool that D can do this (I use it a lot in
>> my
>> code), but I don't feel it's particularly elegant.
>>
>
> 'alias this' is inelegant (sorry Andrei) but it was designed for precisely this purpose - being able to use a struct to wrap any other type, and forward to and override behaviors of that type. Nobody has found a better way.
>

I don't think this is the only instance where alias this is useful though.
It's one of those features that's unintuitive at first, but I find it pops
up surprisingly often.
This is a super common pattern however, and my point was, that language
already has a well defined reference type that is convenient and familiar,
but it comes with some baggage that's not always desired.

It's kind of irrelevant though; the leading point was that one advantage
might be that carrying the vtable beside the instance pointer would
eliminate the hidden fiends in the class instance, but there's the
classinfo pointer too.
Incidentally, why did you go with a dedicated classinfo pointer rather than
use the 1st slot of the vtable like c++?

Fortunately, the inelegance can be encapsulated within that type, and the
> user of the type need not be even aware of it.
>

Sure, but my point was that it seems to be _really_ frequently occurring.
It's relatively unprecedented in D to be happy with such a commitment to
boilerplate like that.
I can imagine there's a strong temptation to just reach for a class even
though it's not appropriate in all situations. It's a lot less cognitive
load; inexperienced programmers won't have trouble with the boilerplate
implementation, or what to do when they hit edge cases.

Remember my halffloat implementation? It relied on 'alias this' to work.
> Just try doing that in C++ <g>.
>

Of course, I use alias this all the time too for various stuff. I said before, it's a useful tool and it's great D *can* do this stuff, but I'm talking about this particular super common use case where it's used to hack together nothing more than a class without a vtable, ie, a basic ref type. I'd say that's worth serious consideration as a 1st-class concept?