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.