November 19, 2009
dsimcha wrote:
> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
>>> 2.  After thinking about this some more, the big issue I see is ref opIndex.  We
>>> can either:
>>>     a.  Disallow it for both UniqueArray and ArrayBuilder.
>>>     b.  Allow it for both UniqueArray and ArrayBuilder and accept
>>>         that a sufficiently dumb programmer can invalidate the
>>>         guarantees of UniqueArray by taking the address of one of the
>>>         elements and saving it somewhere.  Probably a bad idea, since
>>>         assumeUnique() already works for the careful programmer, and
>>>         UniqueArray is supposed to provide ironclad guarantees.
>>>     c.  Don't define opIndex in the abstract base class at all, thus
>>>         making Array almost useless as an abstract base class.
>> Welcome to my demons :o).
>> One possibility that I thought of for a long time would be to disallow
>> taking the address of a ref. That reduces the scope of the problem but
>> doesn't eliminate it:
>> void main() {
>>      auto a = new UniqueArray(10);
>>      fun(a[0], a);
>> }
>> void fun(ref int a, UniqueArray b)
>> {
>>     auto imm = b.toImmutable();
>>     // here a is a mutable alias into an immutable array!!!
>> }
>> So that doesn't work, but I thought I'd mention it :o).
>> Another possibility is to expose opIndex to return by value and also
>> opIndexAssign that sets the value. That would be a no-no in C++ because
>> copying is arbitrarily expensive, but I have a feeling that in D it is
>> sensible to consider and foster that all objects should be defined to be
>> cheap to copy (e.g. refcounting, COW etc.) If we go by the notion that
>> in D we can always assume copy costs are reasonable, this last
>> possibility would work. With the newfangled operators, it would even
>> work beautifully because you can do all sorts of things like a[1] += 4
>> without ever exposing a ref to the user.
>> Andrei
> 
> I wonder if it would be feasible to allow overloading on ref vs. non-ref return.
> Technically this would be overloading on return type, but without many of the
> practical problems.  If the return value is used as an lvalue, the ref return
> function gets called.  If the return value is only used as an rvalue, the non-ref
> function gets called.
> 
> This would allow return by value to be defined in the base class and return by
> reference to only be defined in ArrayBuilder.

It has been discussed. Overloading is not necessary - Walter said defining opIndex and opIndexLvalue and having the compiler call the appropriate one is possible.

Andrei
November 19, 2009
Andrei Alexandrescu, el 18 de noviembre a las 20:33 me escribiste:
> Leandro Lucarella wrote:
> >grauzone, el 19 de noviembre a las 03:47 me escribiste:
> >>Does the current proposal make things simpler at all? All you're doing is to enable the programmer to "fix" the clumsy semantics by throwing lots of CTFE onto the problem. Why not generate the operator functions with CTFE in the first place...
> >
> >I was about to say that, the solution is a hack. I could understand a hack if there were no other way to do it, but you can generate the code for the opXxx using CTFE/string mixins already: we already have a hackish solution. I don't think adding a new hack would be nice (specially when it will be a big change).
> >
> >Maybe a not-so-hackish solution can be found when AST macros get implemented.
> 
> I am thinking that representing operators by their exact token representation is a principled approach because it allows for unambiguous mapping, testing with if and static if, and also allows saving source code by using only one string mixin. It would take more than just a statement that it's hackish to convince me it's hackish. I currently don't see the hackishness of the approach, and I consider it a vast improvement over the current state of affairs.
> 
> I'd be grateful if you argued your point further and hopefully suggested an approach that is better. I want us to move fast with this. So it's just the right time to contribute.

What I found hackish about it is that the code is a string manipulation mess. You can already do a string manipulation mess to programatically implement all the operator overloading.

About the ideal solution, I don't have it. I just have the impression that AST macros can help here, but it's been ages since they were postponed to D3 and I don't have any idea of what they would look like, so I can't propose a solution now.

But what the hell, maybe it's not so bad to have a better solution now, even when not ideal.

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
Los sueños de los niños son especialmente importantes en su etapa de
formación; si un niño no sueña es que será un pelotudo toda la vida.
	-- Ricardo Vaporeso
November 19, 2009
aarti_pl:

> I think that proposed names exactly reflect the meaning. So I would say it is perfectly consistent with D convention.

Dollars are money, but opDollar is not a member function that returns the price of a struct. So I don't agree with you, or I don't understand what you mean.

Bye,
bearophile
November 19, 2009
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
> dsimcha wrote:
> > == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
> >>> 2.  After thinking about this some more, the big issue I see is ref opIndex.  We
> >>> can either:
> >>>     a.  Disallow it for both UniqueArray and ArrayBuilder.
> >>>     b.  Allow it for both UniqueArray and ArrayBuilder and accept
> >>>         that a sufficiently dumb programmer can invalidate the
> >>>         guarantees of UniqueArray by taking the address of one of the
> >>>         elements and saving it somewhere.  Probably a bad idea, since
> >>>         assumeUnique() already works for the careful programmer, and
> >>>         UniqueArray is supposed to provide ironclad guarantees.
> >>>     c.  Don't define opIndex in the abstract base class at all, thus
> >>>         making Array almost useless as an abstract base class.
> >> Welcome to my demons :o).
> >> One possibility that I thought of for a long time would be to disallow
> >> taking the address of a ref. That reduces the scope of the problem but
> >> doesn't eliminate it:
> >> void main() {
> >>      auto a = new UniqueArray(10);
> >>      fun(a[0], a);
> >> }
> >> void fun(ref int a, UniqueArray b)
> >> {
> >>     auto imm = b.toImmutable();
> >>     // here a is a mutable alias into an immutable array!!!
> >> }
> >> So that doesn't work, but I thought I'd mention it :o).
> >> Another possibility is to expose opIndex to return by value and also
> >> opIndexAssign that sets the value. That would be a no-no in C++ because
> >> copying is arbitrarily expensive, but I have a feeling that in D it is
> >> sensible to consider and foster that all objects should be defined to be
> >> cheap to copy (e.g. refcounting, COW etc.) If we go by the notion that
> >> in D we can always assume copy costs are reasonable, this last
> >> possibility would work. With the newfangled operators, it would even
> >> work beautifully because you can do all sorts of things like a[1] += 4
> >> without ever exposing a ref to the user.
> >> Andrei
> >
> > I wonder if it would be feasible to allow overloading on ref vs. non-ref return. Technically this would be overloading on return type, but without many of the practical problems.  If the return value is used as an lvalue, the ref return function gets called.  If the return value is only used as an rvalue, the non-ref function gets called.
> >
> > This would allow return by value to be defined in the base class and return by reference to only be defined in ArrayBuilder.
> It has been discussed. Overloading is not necessary - Walter said
> defining opIndex and opIndexLvalue and having the compiler call the
> appropriate one is possible.
> Andrei

Well, given that Walter's plate is pretty full, how hard would it be to implement this?  I'll probably prototype my ArrayBuilder w/ pure value return and add in opIndexLvalue stuff if/when it becomes available.

Also, are we ever going to do anything about vconst (DIP2)?  For now, I've just been ignoring this issue when I write containers and writing them as if const does not exist, but this is obviously not the correct thing to do. http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2
November 19, 2009
bearophile pisze:
> aarti_pl:
> 
>> I think that proposed names exactly reflect the meaning. So I would say it is perfectly consistent with D convention.
> 
> Dollars are money, but opDollar is not a member function that returns the price of a struct. So I don't agree with you, or I don't understand what you mean.
> 
> Bye,
> bearophile

I agree. opDollar is not particularly fitting to D language operator concept. opLength/opSize would fit better.

In my post I was referring to my name propositions: opInfix, opPrefix, opPostfix.

BR
Marcin Kuszczak
(aarti_pl)
November 19, 2009
dsimcha, el 19 de noviembre a las 17:01 me escribiste:
> > > Unfortunately, I've come to hate the MRU idea because it would fail miserably for large arrays.  I've explained this before, but not particularly thoroughly, so I'll try to explain it more thoroughly here.  Let's say you have an array that takes up more than half of the total memory you are using.  You try to append to it and:
> > >
> > > 1.  The GC runs.  The MRU cache is therefore cleared.
> > >
> > > 2.  Your append succeeds, but the array is reallocated.
> > >
> > > 3.  You try to append again.  Now, because you have a huge piece of garbage that you just created by reallocating on the last append, the GC needs to run again. The MRU cache is cleared again.
> > >
> > > 4.  Goto 2.
> > This is not a matter of principles, but one of implementation. When you GC, you can adjust the cache instead of clearing it.
> 
> Technically true, but what is a matter of principles is whether the implementation of arrays should be very tightly coupled to the implementation of the GC.  Fixing this issue would have massive ripple effects throughout the already spaghetti code-like GC, and might affect GC performance.  For every single object the GC freed, it would have to look through the MRU cache and remove it from there if present, too.
> 
> The point is that this **can** be done, but we probably don't **want** to introduce this kind of coupling, especially if we want our GC model to be sane enough that people might actually come along and write us a better GC one day.

Amen!

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
now self-employed, concerned (but powerless),
an empowered and informed member of society (pragmatism not idealism),
will not cry in public, less chance of illness,
tires that grip in the wet (shot of baby strapped in back seat),
November 19, 2009
On Wed, Nov 18, 2009 at 5:12 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Kyle wrote:
>>
>> Andrei Alexandrescu Wrote:
>>
>>> 6. There must be many things I forgot to mention, or that cause grief to many of us. Please add to/comment on this list.
>>
>> Uniform function call syntax.
>>
>
> It's in the book. I'm adding this message as a reminder to add a test case. Thanks!

It's in the book as working with all types?  Or just built-in array types?

If we're going to have that is there any reason not to have out-of-class operator overloads at last?

If I can do this:

void doSomething(MyClass x) { ... }
MyClass x;
x.doSomething();

Then why not this:
void opUnary(string op)(MyClass x) { ... }
MyClass x;
!x
A.k.a
x.opUnary!("!")();

--bb
November 19, 2009
aarti_pl wrote:
> I know that quite a few people here doesn't like to allow users to define their own operators, because it might obfuscate code. But it doesn't have to be like this. Someone here already mentioned here that it is not real problem for programs in C++. Good libraries don't abuse this functionality.

The problem with user defined operators is:

 1. User defined tokens - mixes up lexing with semantic analysis

 2. User defined syntax - mixes up parsing with semantic analysis

and then we're in C++ land :-(

Unless such have a unique grammar that can be lexed and parsed:

    a :string: b

where string is the user defined name, so you can do things like:

    a :^^: b

and define your own pow operator. The problem with this approach is the sheer ugliness of it.
November 19, 2009
grauzone wrote:
> Like this:
> 
> void main(string[] commandline) {
>     struct Args {
>         string param1 = "can even have default arguments";
>         int param2;
>     }
>     Args args = getopt!(Args)(commandline);
>     writefln("param1 = %s", args.param1);
> }
> 
> No pointers. Instead of returning it, struct could be passed by ref, too.

One nice thing about your proposal is the encapsulating of all the parameters into one struct, instead of them being random variables.

The downside is it spreads out the call to getopt.
November 19, 2009
Andrei Alexandrescu wrote:
> If we use @safe and @trusted to indicate unequivocally "no escape", then there is no analysis to be done - the hard part of the analysis has already been done manually by the user.

The problem then becomes:

T[] foo(T[] t) { return t; }

T[] bar()
{
   T[3] a;
   return foo(a);
}