On 15 May 2012 16:28, Andrei Alexandrescu <seewebsiteforem...@erdani.org>wrote:

> On 5/15/12 8:16 AM, Manu wrote:
>
>> Okay, here's another problem due to ref not being a type constructor.
>> If I have some function that receives an argument by ref, and then I
>> take parameterTypeTuple! of that functions parameter list, the ref bits
>> are gone from the typetuple.
>> If I give that tuple as a template arg, then the template parameters no
>> longer match the function it's wrapping...
>>
>
> Correct. That means there needs to be an additional trait that tells which
> parameters of a function are ref.
>

This just creates a mess, and lots of redundant work. Now, rather than
simply:
  template myTemplate(T...) {}
  myTemplate!(parameterTypeTuple!func)

I need to jump through a whole bunch of hoops to reconstruct an argument
list that actually represents the function args.
I'm CONSTANTLY working around this, I have a file approaching 1000 loc just
full of these sorts of workarounds given different situations.
Most of which elevate the problem beyond a simple template arg to a full
blown string mixin where I have to start coding in between quotes, and with
~ as every second token.


I'm still thinking more and more that there's no solution to all the
>> problems with ref, other than changing it to use the syntax: ref(type),
>> and be a type constructor, like const/immutable/shared/etc...
>> I have problems with ref almost every day. If not in templates, in
>> function/delegate definitions, and the prior issues previously discussed..
>>
>>
>> No matter how I look at it, 'ref' really should be a type constructor.
>>
>
> Ref on a parameter or the return value is a property of the function, not
> a property of the parameter.


I can't agree with that. Whether a parameter is a size_t pointer, or a 10kb
struct is absolutely a property of the parameter. The data actually being
passed is fundamentally different (size_t or buffer), the local storage
mechanism for that data is fundamentally different, it affects the ABI,
interaction with other languages is affected.

Additionally, ref shouldn't only be for function parameters. This is the
source of a bunch more problems.

ref T func();
auto r = func(); <-- r is not a ref. D can't express local references, but
it needs to in many cases.

This is also extremely common in loops to reduce code noise and clutter;
improve readability.

I listed a bunch of problem cases with ref in another thread (thought it
was this one), they would all be solved instantly (and intuitively) if
ref(T) were a type constructor.


The use of 'ref' fundamentally changes the variable from T to T*, that's
>> a critical difference, and can't just be lost when taking the typeof
>> something.
>>
>
> Ref int is not int*


Well... it is and it isn't. It's a pointer with some usage/syntactical
tweaks; must be assigned on declaration, suppress pointer assignment syntax
(enabling regular objective assignment) + arithmetic/indexing suppressed,
etc.


Ref fundamentally dictates how the parameter binds to the argument;
> otherwise, it doesn't affect the behavior of the parameter's type itself.
>

I can see this point, but I don't know if that breaks my argument. Ie. this
isn't a problem, and there are so many real issues with the existing
implementation.


To lift this one level up, what problem are you trying to solve?


1. I can't 'cut and paste' arguments/argument lists from functions to
templates; the ref properties are lost. Leads to bloat, workarounds and
inevitable string mixins.
2. auto doesn't work with ref return values.
3. Syntax is obscure and confused, how to I pass a reference to a function
that returns a ref? Intuitive solution: void func( ref(ref(T) function())
fp )
4. I want to use ref anywhere: ref return values need to assign to ref
locals, loops frequently create a ref as a resolution of a complex lookup
expression for each iteration of the loop, etc.

Right now, the problem is that template args do not transfer the ref-ness
of a given argument; it is an important detail of the type that must be
conveyed.


Perhaps you can clarify why it was done this way; ie, intentionally break
the mould of existing familiar (and perfectly good) implementation like C++
and C#? (C# being a great example of a modern implementation)
There must be some advantages the current implementation offers? I can only
see losses of functionality.

Reply via email to