Thoughts on improving operators

Christophe travert at phare.normalesup.org
Wed Oct 5 04:32:25 PDT 2011


Gor Gyolchanyan , dans le message (digitalmars.D:146100), a écrit :
> I agree. But there's something that can be done to help make the
> operators even more usable.
> Example: named foreach loops over objects:
> 
> struct TestStruct
> {
> public:
>     this(string text) { _text = text.dup; }
> 
>     int opApply(string name : "text")(int delegate(ref dchar) dg)
>     {
>         int result;
>         foreach(ref c; _text)
>         {
>             result = dg(c);
>             if(result)
>                 break;
>         }
>         return result;
>     }
> 
> private:
>     dchar[] _text;
> }
> 
> unittest
> {
>     auto ts = TestStruct("Hello, world!");
>     foreach(ref c; ts.text)
>         if(isAlpha(c))
>             ++c;
>     assert(ts == "Ifmmp, xpsme!");
> }
> 
> Dropping the string name of the operator will mean, using it on the
> object itself (which is the only choice now).
> This would be a very handy way to define more then one type of opApply
> for an object without the need to create and return private structures
> with opApply in them.

This is already possible for opApply.

http://www.d-programming-language.org/statement.html#ForeachStatement

See foreach over delegates.


With your proposal, the parsing of all operators becomes more 
complicated: each time you see a symbol, you must check if it is 
followed by a special operator, if it is, then you don't evaluate the 
symbol, but the operator with this symbol name as template argument. 
Even if the compiler was implemented that way without bugs, you could 
still lose the programmer. I'd prefer to keep the langage simple enough 
so I can see what will get being caller...

In short, I don't know if ts.empty? is going to call ts.empty.opPred, or 
ts.opPred!"empty" ?

I don't think naming predicates is such a big issue. 'isEmpty' is not 
that ugly. And in special cases, you can even decide to call the 
predicate just 'empty'. No one forces you to have a naming convention 
for predicates. If the proposal is used and empty? is used, that doesn't 
change the fact that you should not have a method called empty in your 
structure because of parsing ambiguity, so you could ave used an empty 
method in the first place (instead of isEmpty).

On way to solve this ambiguity would be to use ts?empty. But then you 
lose the ternary operator... And this doesn't work nicely with opIndex 
or opApply, for example.

About using ? as a post-fix unary operator converting to bool, I would 
say 'why not ?'. But I think overloading opPred (and other logical 
operators && and ||) is not a good idea at all. These operators must 
keep the same meaning in any condition.



Finally, if you hate constructing a structure to be used by opIndex, use 
a delegate, and construct the structure on the fly with a template:

struct Indexable(T)
{
  this(T delegate(size_t) dg_) { dg = dg_; }
  T delegate(size_t i) dg;
  T opIndex(size_t i) { return dg(i); }
}

indexable(T)(T delegate(size_t) dg)
{
  return Indexable!T(dg);
}

struct Foo
{
  int a, b;
  auto byIndex()
  {
    return indexable((){ return i==0? a: b; })
  }
}


We could even improve the template by templating the index argument, 
proposing to have a length method, etc...

-- 
Christophe


More information about the Digitalmars-d mailing list