Thoughts on improving operators

Gor Gyolchanyan gor.f.gyolchanyan at gmail.com
Wed Oct 5 03:26:26 PDT 2011


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.
The same thing can be used for any other operator, including slices,
indices, etc...
This is very different from returning a ref, because two slice
operators with different names could slice the same object in
different way (e.g. slice a matrix by rows or columns).
The idea is similar to having properties: you _can_ achieve the same
effect without properties by creating and returning private structures
with the operators overloaded, but this allows to save lots of time
and run-time overhead.
Much like an integrated opDispatch in each operator.
This seems to introduce ambiguity with calling the operators for the
members, but there is more then one solution to this:
    * Either disallow using names, already used by members.
    * Or make the member-operator more prioritized, then the named
operator call, allowing it to run only if no member of that name is
accessible from the point of the call.
    * Or make all operators to members as named operators, that the
compiler automatically generates (like the default constructor for
classes) and allow the client to override or disable them.
Best of all, this does not in any way break existing code.

Introduce another operator opPred:

struct TestStruct
{
    int[] array;

    bool opPred(string name: empty)()
    {
        return array.length == 0;
    }
}

unittest
{
    TestStruct ts;
    if(ts.empty?) writeln("yes, it is.");
   bool delegate() isEmpty = &ts.empty?;
   bool isIt = ts.empty ? true : false;
}

This really looks like it's gonna make D context-dependent and break
lots of code, but:

The question mark becomes the opPred operator, which:
    * Either returns bool (when a colon isn't followed).
    * Or evaluates one of the expressions (if the colon is followed
and it is a ternary if operator).

The question mark is only used in the ternary operator, so there is no
other way to interpret it.
The question mark can be syntactically interpreted as one of two
possible expressions (either with or without the following colon),
which cannot be ambiguous, because the colon also has a very limited
and specific use.
of course, the question mark, as with the ternary operator, will have
the lowest precedence, to allow taking delegate of and generally
following the ternary operator's behavior.
What do you think?
Wouldn't this solve the aforementioned problem with predicates without
breaking anything?

On Wed, Oct 5, 2011 at 11:54 AM, Walter Bright
<newshound2 at digitalmars.com> wrote:
> On 10/4/2011 2:46 AM, Jacob Carlborg wrote:
>>
>> What are the thoughts around here on function names containing arbitrary
>> symbols, like in Scala. Example:
>>
>> void ::: (int a) {}
>
> This, in effect, means "user defined tokens". The lexing pass will then
> become intertwined with semantic analysis. While possible, this will make
> the compiler slow, buggy, impossible to run the passes concurrently, hard to
> write 3rd party parsing tools, etc.
>


More information about the Digitalmars-d mailing list