October 15, 2010
Easy, just implement a small assembly funtion.

Not everything has to be in the language.

"Walter Bright" <newshound2@digitalmars.com> wrote in message news:i984lr$odj$3@digitalmars.com...
> Walter Bright wrote:
>> It's hard to see how to implement, say, a storage allocator with no pointer arithmetic.
>
> Here's another one. Try implementing va_arg without pointer arithmetic.


October 15, 2010
Yeah, and I've done that. It doesn't work out as well as you say, nor is it that easy. Problems:

1. You have to reimplement it for every platform and every memory model.
2. For some systems, like Windows, there are a wide variety of assemblers. They all use slightly different syntax. Distributing an asm file means an *unending* stream of complaints from people who don't have an assembler or have a different one than yours.
3. Getting all the boilerplate segment declarations right is a nuisance.
4. Name mangling.
5. Next your asm code all breaks when you want to recompile your app as a shared library.
6. Asm files are a nightmare on OSX.

A language should be there to solve problems, not create them :-)

Paulo Pinto wrote:
> Easy, just implement a small assembly funtion.
> 
> Not everything has to be in the language.
> 
> "Walter Bright" <newshound2@digitalmars.com> wrote in message news:i984lr$odj$3@digitalmars.com...
>> Walter Bright wrote:
>>> It's hard to see how to implement, say, a storage allocator with no pointer arithmetic.
>> Here's another one. Try implementing va_arg without pointer arithmetic. 
> 
> 
October 15, 2010
"Walter Bright" <newshound2@digitalmars.com> wrote in message news:i98frv$1dm2$1@digitalmars.com...
> bearophile wrote:
>> Nick Sabalausky:
>>
>>> Then you're wasting cycles every iteration (by doing an extra addition and maybe an extra shift or even multiplication depending on T: Ie, (cast(ubyte*)myArray.ptr) + i * T.sizeof). That was a pretty common inner-loop optimization back in my C days.
>>
>> With D sometimes array-based code is faster than pointer-based. With LDC they are usually equally efficient.
>
> ??? This makes no sense.
>
> The (ptr+i*T.sizeof) is an addressing mode on the x86, and comes at ZERO cost.

As long as T.sizeof is either 1, 2, 4, or 8 bytes.


October 15, 2010
On 10/15/2010 05:55 AM, Walter Bright wrote:

>
> D has pointers that you cannot do arithmetic on - called references. The
> semantics are carefully designed so a function cannot return a reference
> to a local, this is so that such locals will not have to be put onto the
> garbage collected heap. Hence, references are usable in safe mode.

I think the above statement needs clarification. Honestly, I don't understand how references to non-class objects are supposed to work in SafeD. Consider:

struct S
{
    int x;
}

static S s;
ref S foo()
{
    return s;
}

void bar()
{
    foo().x = 1;
    assert(s.x == 1); // ok, s updated

    auto s2 = foo();
    s2.x = 2;
    assert(s.x == 2); // not ok, we need to use a pointer as below

    auto s3 = &foo();
    s3.x = 3;
    assert(s.x == 3); // ok, s updated
}

Since pointers are not allowed in SafeD, any non-trivial operations on a referenced object are extremely awkward because you have to pile all of them around the call returning the reference. For example, if I want to update s and then pass it by reference to another function:

void baz(ref S s)
{
}

void bar()
{
    baz(foo(s).x = 1); // awkward
}

Of course, we can use tricks like a @trusted Ref struct wrapping a pointer to the referenced object. But I don't know how such a struct can prevent one from returning locals:

struct Ref(T)
{
    T* p;
    this(ref T v) { p = &v; }
    ref T getRef() { return *p; }
    alias getRef this;
}

ref Ref!T byref(T)(ref T v)
{
    return Ref!T(v);
}

ref S foo()
{
    S s;
    return byref(s); // local successfully escaped
}

Please comment.


October 15, 2010
On 10/15/2010 11:49 AM, Max Samukha wrote:

> ref Ref!T byref(T)(ref T v)
> {
>      return Ref!T(v);
> }

should be

Ref!T byref(T)(ref T v)
{
    return Ref!T(v);
}

October 15, 2010
On 10/15/2010 11:49 AM, Max Samukha wrote:

...and

> void bar()
> {
>     baz(foo(s).x = 1); // awkward
> }
>

should be

void bar()
{
    baz(foo().x = 1); // awkward
}
October 15, 2010
Still most modern languages are moving away from inline assembly.

Even Microsoft has dropped inline assembly support for the 64bit version of
Visual C++, pointing
developers to MASM.

People will always complain no matter what. Just use the official assembler for the target platform.

Personally the last time I used inline assembly I was still target MS-DOS,
long time ago and actually
it is one of the features I don't like in D.

--
Paulo

"Walter Bright" <newshound2@digitalmars.com> wrote in message news:i98ub5$2bk7$1@digitalmars.com...
> Yeah, and I've done that. It doesn't work out as well as you say, nor is it that easy. Problems:
>
> 1. You have to reimplement it for every platform and every memory model.
> 2. For some systems, like Windows, there are a wide variety of assemblers.
> They all use slightly different syntax. Distributing an asm file means an
> *unending* stream of complaints from people who don't have an assembler or
> have a different one than yours.
> 3. Getting all the boilerplate segment declarations right is a nuisance.
> 4. Name mangling.
> 5. Next your asm code all breaks when you want to recompile your app as a
> shared library.
> 6. Asm files are a nightmare on OSX.
>
> A language should be there to solve problems, not create them :-)
>
> Paulo Pinto wrote:
>> Easy, just implement a small assembly funtion.
>>
>> Not everything has to be in the language.
>>
>> "Walter Bright" <newshound2@digitalmars.com> wrote in message news:i984lr$odj$3@digitalmars.com...
>>> Walter Bright wrote:
>>>> It's hard to see how to implement, say, a storage allocator with no pointer arithmetic.
>>> Here's another one. Try implementing va_arg without pointer arithmetic.
>> 

October 15, 2010
Max Samukha wrote:
> Please comment.

The example relies on taking the address of a ref in a safe function. To close this hole, it appears that should be disallowed.
October 15, 2010
Then don't use that feature, what is wrong with having a feature you don't use?

> Personally the last time I used inline assembly I was still target MS-DOS,
> long time ago and actually
> it is one of the features I don't like in D.
>
> --
> Paulo
>
> "Walter Bright" <newshound2@digitalmars.com> wrote in message
> news:i98ub5$2bk7$1@digitalmars.com...
>> Yeah, and I've done that. It doesn't work out as well as you say, nor is
>> it that easy. Problems:
>>
>> 1. You have to reimplement it for every platform and every memory model.
>> 2. For some systems, like Windows, there are a wide variety of assemblers.
>> They all use slightly different syntax. Distributing an asm file means an
>> *unending* stream of complaints from people who don't have an assembler or
>> have a different one than yours.
>> 3. Getting all the boilerplate segment declarations right is a nuisance.
>> 4. Name mangling.
>> 5. Next your asm code all breaks when you want to recompile your app as a
>> shared library.
>> 6. Asm files are a nightmare on OSX.
>>
>> A language should be there to solve problems, not create them :-)
>>
>> Paulo Pinto wrote:
>>> Easy, just implement a small assembly funtion.
>>>
>>> Not everything has to be in the language.
>>>
>>> "Walter Bright" <newshound2@digitalmars.com> wrote in message
>>> news:i984lr$odj$3@digitalmars.com...
>>>> Walter Bright wrote:
>>>>> It's hard to see how to implement, say, a storage allocator with no
>>>>> pointer arithmetic.
>>>> Here's another one. Try implementing va_arg without pointer arithmetic.
>>>
>


-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
October 15, 2010
On 10/15/2010 12:32 PM, Walter Bright wrote:
>
> The example relies on taking the address of a ref in a safe function. To
> close this hole, it appears that should be disallowed.

And disallowing it makes references not so useful.

What I like about Go's solution is that it is consistent with closures. When a group of locals escape with a closure (that is when the address of the local function using that group is taken) they are copied to heap. When a local escape by ref (that is when the address of the local is taken), it is also copied to heap.

What I don't like about Go's closures/addresses-to-locals and D's delegates is that stuff is heap-allocated implicitly and by default. Go has even gone (sorry) as far as allocating copies *every* time the address of a local is taken.

That reminds me of the argument about "new" being necessary for classes because it makes the heap allocation explicit. It is difficult to say good-bye to "new" but at the same time we are somehow happy with implicitly allocated closures.