View mode: basic / threaded / horizontal-split · Log in · Help
February 07, 2013
Re: DIP25 draft available for destruction
On 2/7/2013 3:16 AM, deadalnix wrote:
>>> The 'funny' things is that C#'s would cause syntax problem issue with address
>>> of,
>>> where D does.
>>
>> I don't understand this sentence.
>>
>
> In C#, foo.bar won't execute bar's method of foo. It will get what is called in
> D a delegate. foo.bar() execute that delegate.
>
> It remove the need for &foo.bar altogether, so with that mechanism in D, no
> problem with & operator.
>
> Scala does even one step further by executing the method, or not, depending on
> what is expected, proving that optional () are compatible with.
>
> Back to D, we have void function() foo; foo is declared as a function here.

No, that declares foo as a "pointer to function".


> Now you can pass several object to templates alias parameters, that will behave
> differently in slightly different subtle ways. For no real good reason.

They won't behave any differently than they would outside of being passed as 
aliases. I don't see a special problem added with alias parameters.


>>> I don't think it is, and looking at other languages choices, I'm not alone.
>>
>> Given the vast variety and complexity of languages out there, for every
>> example of A you can find, I can find examples of !A. It's not really useful,
>> after all, if other languages got it all right, there's no point to D.
> If A is the instruction pack entity type mentionned above, you'll find pretty
> hard to find a !A if we exclude C and C++ (well and D, but it is kind of
> excluded if look for references). I don't pretend none exists, but it seems
> pretty hard to find one.

There are few languages in the systems programming category (languages that give 
one full access to pointers), so excluding C and C++ seems rather draconian.


> He does so by adding special cases. That is the problem with special cases, they
> multiply themselves faster than rabbits.

Taking the address of a ref was already problematic.
February 08, 2013
Re: DIP25 draft available for destruction
On Thursday, 7 February 2013 at 19:49:27 UTC, Walter Bright wrote:
> On 2/7/2013 6:15 AM, Zach the Mystic wrote:
>> Can you tell me if you consider my proposal with regard to 
>> making ref safe and
>> complete simple and intuitive both for compiler and user, and 
>> if not, why? (I
>> don't have an opinion about '&' yet.)
>>
>> http://forum.dlang.org/thread/ket199$2c27$1@digitalmars.com#post-bsgrtofehxfjmzkaedfr:40forum.dlang.org
>>
>
> I don't know if it's complete and safe. It's not something that 
> can be determined with a quick read.

Okay. But at least that's a 'check' on simple and intuitive?

As far as why I think it's safe, my investigation led me to 
conclude that the key question was, how do I know whether to 
treat the return value of a ref function which accept a ref as 
local or global? I pass a value into a mysterious box, how do I 
know whether what comes out the other end is related to what I 
passed in, or something completely different? All the cases DIP25 
takes care of are the ones which can be known just by the 
peculiarities of the call and signature, but many cases just 
leave you in the dark. The only way the compiler can know for 
sure without help from the function signature is by dipping into 
the function's code to take a look, which seems like too high a 
price to pay. About a month ago Jonathan M Davis brought this up 
and pointed out that the PIMPL idiom occasionally banishes 
altogether that opportunity for the compiler.

After a few tries, I realized that 'out' was actually still 
available to use for this purpose, which is either pure luck 
(possible) or a hidden byproduct of the fact that 1) it's a good 
keyword to begin with or 2) there's a secret truth to its 
interchangeability with 'ref' which applies to return values as 
well as to parameter tags.
February 08, 2013
Re: DIP25 draft available for destruction
On Thursday, 7 February 2013 at 14:43:38 UTC, Steven 
Schveighoffer wrote:
> On Thu, 07 Feb 2013 01:06:34 -0500, Walter Bright 
> <newshound2@digitalmars.com> wrote:
>
>>
>> The only time (now) that you can take the address of function 
>> return value is if that is a return by ref. So, if taking the 
>> address of a ref is disallowed, then the syntax is no longer 
>> ambiguous.
>
> Thinking about this, I don't know that I like the idea of 
> disallowing taking the address of ref.
>
> One major usage of taking the address of ref returns is the 
> opIndex operator:
>
> int *ptr = &arr[0];
>
> Or, more generally, the front property of a range:
>
> int *ptr = &arr.front;
>
> What I am concerned about is that this is not going to have the 
> desired effect.  Instead of grudgingly switching to a new style 
> of coding, people will simply return pointers instead of ref.
>

Exactly.
February 08, 2013
Re: DIP25 draft available for destruction
On Thursday, 7 February 2013 at 19:57:50 UTC, Walter Bright wrote:
> On 2/7/2013 3:16 AM, deadalnix wrote:
>>>> The 'funny' things is that C#'s would cause syntax problem 
>>>> issue with address
>>>> of,
>>>> where D does.
>>>
>>> I don't understand this sentence.
>>>
>>
>> In C#, foo.bar won't execute bar's method of foo. It will get 
>> what is called in
>> D a delegate. foo.bar() execute that delegate.
>>
>> It remove the need for &foo.bar altogether, so with that 
>> mechanism in D, no
>> problem with & operator.
>>
>> Scala does even one step further by executing the method, or 
>> not, depending on
>> what is expected, proving that optional () are compatible with.
>>
>> Back to D, we have void function() foo; foo is declared as a 
>> function here.
>
> No, that declares foo as a "pointer to function".
>

That isn't what I read. It is clearly written void function() 
foo; And if in int a; a is an int and in int* b, b is a pointer 
on int, foo must be a function. The fact that this very entity 
type is called function pointer is C is irrelevant.

The distinction between the 2 is a problem in the first place, as 
it create new entities with different behavior, for a benefice 
that is unclear to me.

>> Now you can pass several object to templates alias parameters, 
>> that will behave
>> differently in slightly different subtle ways. For no real 
>> good reason.
>
> They won't behave any differently than they would outside of 
> being passed as aliases. I don't see a special problem added 
> with alias parameters.
>

Because the same syntax have different meanings, so suddenly, you 
have to special case everything. That is never done in practice, 
not even in phobos.

>> If A is the instruction pack entity type mentionned above, 
>> you'll find pretty
>> hard to find a !A if we exclude C and C++ (well and D, but it 
>> is kind of
>> excluded if look for references). I don't pretend none exists, 
>> but it seems
>> pretty hard to find one.
>
> There are few languages in the systems programming category 
> (languages that give one full access to pointers), so excluding 
> C and C++ seems rather draconian.
>

I don't see why this should be limited to system languages. This 
is about function and most languages have functions (and most 
modern languages have first class functions).

Additionally, as show with scala or C#, the semantic of theses 
language often do not conflict with pointer access.

>> He does so by adding special cases. That is the problem with 
>> special cases, they
>> multiply themselves faster than rabbits.
>
> Taking the address of a ref was already problematic.

Yes indeed. I never argued against that.
February 08, 2013
Re: DIP25 draft available for destruction
On 02/06/2013 02:38 AM, Andrei Alexandrescu wrote:
> Probably it'll need a fair amount of tweaking. Anyhow it's in
> destroyable form.
>
> http://wiki.dlang.org/DIP25
>
>
> Thanks,
>
> Andrei

A single delegate (closure) can be used to defer both reads and writes 
on an arbitrary expression.

This works on naked variables, references, pointers, properties, and 
probably a number of other things I haven't thought of yet.

Here's the relevance to DIP25: closures already have well-defined escape 
semantics.  The downside is that they probably allocate heap way too 
aggressively in the current implementation.  The upshot is that they are 
always memory-safe.  This makes optimization a quality-of-implementation 
issue: a sufficiently intelligent compiler should be able to remove many 
allocations for non-escaping closures.

Perhaps ref parameters should be delegates under the hood instead of 
pointers?

The longterm disadvantage I see with this is the extra pointer that must 
be passed/returned.  I wonder how hard it would be for the compiler to 
instantiate specialized oldschool-pointer versions of functions with ref 
parameters whenever calls are made that do not require the guarantees 
that closures provide.

A working demonstration is given below.

Destroy!


import std.traits;
import std.stdio;

struct Option(T)
{
    bool hasValue = false;
    union
    {
        ubyte nope;
        T value;
    }

    this( T value )
    {
        hasValue = true;
        this.value = value;
    }
}

Option!T none(T)()
{
    Option!T result;
    return result;
}

/* For some reason we need to cast to this to make template deduction 
work on any functions it gets passed into. */
template DelegateRef(T)
{
    alias T delegate(Option!T intake) DelegateRef;
}

template isDelegateRef(T)
{
    static if ( isDelegate!T )
    {
        alias ReturnType!T R;
        static if ( is( T == R delegate(Option!R) ) )
            enum isDelegateRef = true;
        else
            enum isDelegateRef = false;
    }
    else
        enum isDelegateRef = false;
}

string accessor(string expr)
{
    return
        `cast(DelegateRef!(typeof(`~expr~`))) (`~
        `delegate typeof(`~expr~`)(Option!(typeof(`~expr~`)) intake) {`~
        `    if ( intake.hasValue )`~
        `        return (`~expr~` = intake.value);`~
        `    else`~
        `        return `~expr~`;`~
        `})`;
}

// Function that accepts a reference.
auto someFunc(Q)(Q qux) if ( isDelegateRef!Q )
{
    alias ReturnType!Q T;
    auto x = qux(none!T);
    x |= 0xF00D;
    qux(Option!T(x));
    return qux(none!T);
}

struct MyStruct
{
    private int m_q;

    @property int q()
    {
        writefln("get q (%x)",m_q);
        return m_q;
    }

    @property int q(int v)
    {
        writefln("set q (%x = %x)", m_q, v);
        return m_q = v;
    }
}

void testRef( ref int foo )
{
    assert(someFunc(mixin(accessor("foo"))) == 0xF00D);
}

void testPtr( int* foo )
{
    assert(someFunc(mixin(accessor("*foo"))) == 0xF00D);
}

void main()
{
    int abc = 0;
    assert(someFunc(mixin(accessor("abc"))) == 0xF00D);
    assert(abc == 0xF00D);

    int foo = 0;
    testRef(foo);
    assert(foo == 0xF00D);

    int bar = 0;
    testPtr(&bar);
    assert(bar == 0xF00D);

    MyStruct s;
    s.q = 0;
    assert(someFunc(mixin(accessor("s.q"))) == 0xF00D);
    assert(s.q == 0xF00D);
}
February 08, 2013
Re: DIP25 draft available for destruction
On Friday, 8 February 2013 at 06:28:54 UTC, Chad Joan wrote:
> On 02/06/2013 02:38 AM, Andrei Alexandrescu wrote:
>> Probably it'll need a fair amount of tweaking. Anyhow it's in
>> destroyable form.
>>
>> http://wiki.dlang.org/DIP25
>>
>>
>> Thanks,
>>
>> Andrei
>
> A single delegate (closure) can be used to defer both reads and 
> writes on an arbitrary expression.
>
> This works on naked variables, references, pointers, 
> properties, and probably a number of other things I haven't 
> thought of yet.
>
> Here's the relevance to DIP25: closures already have 
> well-defined escape semantics.  The downside is that they 
> probably allocate heap way too aggressively in the current 
> implementation.  The upshot is that they are always 
> memory-safe.  This makes optimization a 
> quality-of-implementation issue: a sufficiently intelligent 
> compiler should be able to remove many allocations for 
> non-escaping closures.
>
> Perhaps ref parameters should be delegates under the hood 
> instead of pointers?
>
> The longterm disadvantage I see with this is the extra pointer 
> that must be passed/returned.  I wonder how hard it would be 
> for the compiler to instantiate specialized oldschool-pointer 
> versions of functions with ref parameters whenever calls are 
> made that do not require the guarantees that closures provide.
>
> A working demonstration is given below.
>
> Destroy!
>

The cost of passing a delegate is way higher than the cost of 
passing the extra pointer. Delegate cause an opaque function call 
so :
 - All registers that the callee is allowed to trash must be 
saved preventively (even if the callee don't trash them).
 - CPU cannot really use branch prediction.
 - The compiler must assume that the delegate call may have 
arbitrary side effects so have to commit everything to memory and 
then take everything back afterward. This prevent many 
instruction reordering, register promotions, dead read/write 
elimination, constant propagation and so on.

Considering passing by ref is sometime done to fasten things, 
this defeat the whole point.

Note that the operation above are not dying slow, but clearly not 
a good fit for ref.

>
> import std.traits;
> import std.stdio;
>
> struct Option(T)
> {
>     bool hasValue = false;
>     union
>     {
>         ubyte nope;
>         T value;
>     }
>
>     this( T value )
>     {
>         hasValue = true;
>         this.value = value;
>     }
> }
>
> Option!T none(T)()
> {
>     Option!T result;
>     return result;
> }
>
> /* For some reason we need to cast to this to make template 
> deduction work on any functions it gets passed into. */
> template DelegateRef(T)
> {
>     alias T delegate(Option!T intake) DelegateRef;
> }
>
> template isDelegateRef(T)
> {
>     static if ( isDelegate!T )
>     {
>         alias ReturnType!T R;
>         static if ( is( T == R delegate(Option!R) ) )
>             enum isDelegateRef = true;
>         else
>             enum isDelegateRef = false;
>     }
>     else
>         enum isDelegateRef = false;
> }
>
> string accessor(string expr)
> {
>     return
>         `cast(DelegateRef!(typeof(`~expr~`))) (`~
>         `delegate typeof(`~expr~`)(Option!(typeof(`~expr~`)) 
> intake) {`~
>         `    if ( intake.hasValue )`~
>         `        return (`~expr~` = intake.value);`~
>         `    else`~
>         `        return `~expr~`;`~
>         `})`;
> }
>
> // Function that accepts a reference.
> auto someFunc(Q)(Q qux) if ( isDelegateRef!Q )
> {
>     alias ReturnType!Q T;
>     auto x = qux(none!T);
>     x |= 0xF00D;
>     qux(Option!T(x));
>     return qux(none!T);
> }
>
> struct MyStruct
> {
>     private int m_q;
>
>     @property int q()
>     {
>         writefln("get q (%x)",m_q);
>         return m_q;
>     }
>
>     @property int q(int v)
>     {
>         writefln("set q (%x = %x)", m_q, v);
>         return m_q = v;
>     }
> }
>
> void testRef( ref int foo )
> {
>     assert(someFunc(mixin(accessor("foo"))) == 0xF00D);
> }
>
> void testPtr( int* foo )
> {
>     assert(someFunc(mixin(accessor("*foo"))) == 0xF00D);
> }
>
> void main()
> {
>     int abc = 0;
>     assert(someFunc(mixin(accessor("abc"))) == 0xF00D);
>     assert(abc == 0xF00D);
>
>     int foo = 0;
>     testRef(foo);
>     assert(foo == 0xF00D);
>
>     int bar = 0;
>     testPtr(&bar);
>     assert(bar == 0xF00D);
>
>     MyStruct s;
>     s.q = 0;
>     assert(someFunc(mixin(accessor("s.q"))) == 0xF00D);
>     assert(s.q == 0xF00D);
> }
February 08, 2013
Re: DIP25 draft available for destruction
On 02/08/2013 02:06 AM, deadalnix wrote:
> On Friday, 8 February 2013 at 06:28:54 UTC, Chad Joan wrote:
>>
>> Destroy!
>>
>
> The cost of passing a delegate is way higher than the cost of passing
> the extra pointer. Delegate cause an opaque function call so :
> - All registers that the callee is allowed to trash must be saved
> preventively (even if the callee don't trash them).
> - CPU cannot really use branch prediction.
> - The compiler must assume that the delegate call may have arbitrary
> side effects so have to commit everything to memory and then take
> everything back afterward. This prevent many instruction reordering,
> register promotions, dead read/write elimination, constant propagation
> and so on.
>
> Considering passing by ref is sometime done to fasten things, this
> defeat the whole point.
>
> Note that the operation above are not dying slow, but clearly not a good
> fit for ref.
>

Fair enough.

I wonder if we can learn something from it though.  It does seem to 
provide a conceptual model that's very desirable.
February 09, 2013
Re: DIP25 draft available for destruction
Two more things:

Disable a read/write propa like int getSetSomeInteger(int).
int getSomeInteger() and void setSomeIntger(int) only allowed.

And disable default parameter for setter.
February 10, 2013
Re: DIP25 draft available for destruction
Am Wed, 06 Feb 2013 22:11:40 -0800
schrieb Walter Bright <newshound2@digitalmars.com>:

> On 2/6/2013 4:23 PM, Andrej Mitrovic wrote:
> > On 2/6/13, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> >> Pointers are what they are, and they're not appropriate for
> >> code that offers guarantees.
> >
> > But we're talking about @system here. I would probably be fine with
> > these rules if they only applied to @safe.
> >
> > I feel like someone is trying to put training wheels on my mountain bike.
> >
> 
> One reason why @safe is not the default.

It would also be very very nice, if we could at least write
"Hello, world!" in @safe D.

-- 
Marco
February 10, 2013
Re: DIP25 draft available for destruction
On Wednesday, 6 February 2013 at 21:40:00 UTC, Andrei 
Alexandrescu wrote:
> On 2/6/13 3:02 PM, Andrej Mitrovic wrote:
>> Also the DIP argues that addressOf solves the @property issue 
>> w.r.t.
>> return values. I've proposed we use an .addressOf property 
>> which only
>> works on @property functions, and I saw no arguments against 
>> it.
>
> There aren't, but a library approach is better than a magic 
> work, all other things being equal.
>
>
> Andrei

struct S
{
  @property int var();
  @property void var(int);
}

The .addressOf property gave me the idea of solving the 
getter/setter issue, by having two properties...

var.getter
var.setter

maybe it could be added to your library approach though?
3 4 5 6 7 8
Top | Discussion index | About this forum | D home