Thread overview
Lazy range of hashes?
Aug 25, 2012
Andrej Mitrovic
Aug 26, 2012
bearophile
Aug 26, 2012
Andrej Mitrovic
Aug 26, 2012
Ali Çehreli
Aug 26, 2012
Era Scarecrow
Aug 26, 2012
Ali Çehreli
Aug 26, 2012
Artur Skawina
Aug 26, 2012
Era Scarecrow
August 25, 2012
I could use something like this:

void main()
{
    int[string] x = ["foo":1];
    int[string] y = ["bar":1];
    assert("bar" in lazyHash(x, y));
}

Essentially it would turn into lazy 'in' checks, meaning first opIn_r would be called for 'x', and then for 'y'.

Otherwise it might be expensive to have to create a new hash that has all the keys and values of other hashes. Has anyone ever implemented this?
August 26, 2012
Andrej Mitrovic:

> void main()
> {
>     int[string] x = ["foo":1];
>     int[string] y = ["bar":1];
>     assert("bar" in lazyHash(x, y));
> }
>
> Essentially it would turn into lazy 'in' checks, meaning first opIn_r
> would be called for 'x', and then for 'y'.

This seems to work:

import std.algorithm;
void main() {
    auto x = ["foo": 1];
    auto y = ["bar": 2];
    //assert("bar" in lazyHash(x, y));
    assert(any!(h => "bar" in h)([x, y]));
}

Recently I have seen a lazy range struct able to replace that
[x,y]. I don't know if it's in Phobos already.

Bye,
bearophile
August 26, 2012
On 8/26/12, bearophile <bearophileHUGS@lycos.com> wrote:
> This seems to work:

It seems it's as simple as defining a struct:

struct LazyHash(T...)
{
    T hashes;

    bool opIn_r(X)(X x)
    {
        foreach (hash; hashes)
        {
            if (x in hash)
                return true;
        }

        return false;
    }
}

auto lazyHash(T...)(T t)
{
    return LazyHash!T(t);
}

void main()
{
    auto x = ["foo" : 1];
    auto y = ["bar" : 2];

    assert("bar" in lazyHash(x, y));
    assert("barx" !in lazyHash(x, y));
}

I didn't even have to define a ctor since field assignment works.
August 26, 2012
On 08/25/2012 05:30 PM, Andrej Mitrovic wrote:
> On 8/26/12, bearophile<bearophileHUGS@lycos.com>  wrote:
>> This seems to work:
>
> It seems it's as simple as defining a struct:
>
> struct LazyHash(T...)
> {
>      T hashes;
>
>      bool opIn_r(X)(X x)
>      {
>          foreach (hash; hashes)
>          {
>              if (x in hash)
>                  return true;
>          }
>
>          return false;
>      }
> }
>
> auto lazyHash(T...)(T t)
> {
>      return LazyHash!T(t);
> }
>
> void main()
> {
>      auto x = ["foo" : 1];
>      auto y = ["bar" : 2];
>
>      assert("bar" in lazyHash(x, y));
>      assert("barx" !in lazyHash(x, y));
> }
>
> I didn't even have to define a ctor since field assignment works.

Cool! :) If the operator returns the pointer to the element, then the callers can access its value as well:

    auto opIn_r(X)(X x)
    {
        foreach (hash; hashes)
        {
            auto p = x in hash;
            if (p)
                return p;    // <-- return the pointer
        }

        return null;
    }

// ...

    import std.stdio;

    auto p = "foo" in lazyHash(x, y);
    if (p) {
        writeln(*p);    // <-- the user can access the value
    }

Ali
August 26, 2012
On Sunday, 26 August 2012 at 07:29:13 UTC, Ali Çehreli wrote:
> Cool! :) If the operator returns the pointer to the element, then the callers can access its value as well

 Reminds me, although not for you Ali, but as a pointer return a question came up. I've wondered and haven't tested this but hypothetically:

 Due to that you can call structures and class members even from a pointer (transparently compared to C/C++), does it automatically convert from a pointer to a non-pointer type if the return calls for it? In a class that's irrelevant (it's already a reference type and should auto-fix itself); But a struct or non-class?

 //just to get the idea
 //potentially ref int, rather than int* as well
 int getSomeValue(int[string] x, string someValue) {
   auto sv = someValue in x;
   return x ? x : 0; //auto convert? Or error? If not, why?
 }

 Rather than auto could ref work? Or if it's a exact valueType (with postblitz) or (known to be relocatable) would it make a new copy? I can see the importance of both, but depending on the return type in cases, having it throw an error seems like the best policy if it's a non-built in, since it's trivial changing return x, with return *x; Also as a built in type it could automatically do the copy/conversion for you.
August 26, 2012
On 08/26/2012 12:55 AM, Era Scarecrow wrote:
> On Sunday, 26 August 2012 at 07:29:13 UTC, Ali Çehreli wrote:
>> Cool! :) If the operator returns the pointer to the element, then the
>> callers can access its value as well
>
> Reminds me, although not for you Ali, but as a pointer return a question
> came up. I've wondered and haven't tested this but hypothetically:
>
> Due to that you can call structures and class members even from a
> pointer (transparently compared to C/C++),

It has been argued that the -> operator has not been needed for C anyway.

Interestingly, it has some value in C++ because if a type has defined operator->() (rather, for this discussion, operator.(), which does not exist in C++ today), then the following would cause confusion for types that worked like smart pointers:

class P
{
    /* hypothetical operator */
    T * operator.();
    void foo();
};

    P p = bar();
    p.foo(); // foo() of the pointer type or the 'pointed to type'?

D does not have that question because the dot operator may not be overloaded. (opDot() has been (will be?) deprecated.)

> does it automatically convert
> from a pointer to a non-pointer type if the return calls for it?

No: The dot does not convert the type. The dot has different meanings on structs vs. classes. With structs, it always operates on the struct object:

    o.sizeof   // The size of the struct object
    o.foo()    // The member of the struct object

With classes, it operates sometimes on the reference and sometimes on the referenced object:

    o.sizeof   // The size of the class reference
    o.foo()    // The member of the class object

That's D's way of confusing on this topic.

> In a
> class that's irrelevant (it's already a reference type and should
> auto-fix itself); But a struct or non-class?
>
> //just to get the idea
> //potentially ref int, rather than int* as well
> int getSomeValue(int[string] x, string someValue) {
> auto sv = someValue in x;
> return x ? x : 0; //auto convert? Or error? If not, why?

You meant sv:

    return sv ? sv : 0;

That is still a compilation error for a statically-typed language like D. The types of sv and 0 don't match. But the line should always be like this anyway:

    return sv ? *sv : 0;

Because sv is always a pointer:

  // For a struct pointer:
  *sv  // a reference to the struct object

  // For a class reference:
  *sv is another reference to the actual class object

> Rather than auto could ref work?

You mean, 'ref' on the return type, right? For opIn_r, it better not be 'ref', because then it would be returning a reference to a local pointer:

    // Note ref return. I think this is a bug.
    ref opIn_r(X)(X x)
    {
        foreach (hash; hashes)
        {
            auto p = x in hash;
            if (p)
                return p; // <-- return a reference to the local pointer
        }

        return null;
    }

I think that is a bug but the compiler does not give a warning about returning a reference to the local pointer.

> Or if it's a exact valueType (with
> postblitz) or (known to be relocatable) would it make a new copy? I can
> see the importance of both, but depending on the return type in cases,
> having it throw an error seems like the best policy if it's a non-built
> in, since it's trivial changing return x, with return *x; Also as a
> built in type it could automatically do the copy/conversion for you.

As you said, returning *x would return a copy of the value if it were a struct.

Ali

August 26, 2012
On 08/26/12 17:28, Ali Çehreli wrote:
> On 08/26/2012 12:55 AM, Era Scarecrow wrote:
>> On Sunday, 26 August 2012 at 07:29:13 UTC, Ali Çehreli wrote:
>>> Cool! :) If the operator returns the pointer to the element, then the callers can access its value as well
>>
>> Reminds me, although not for you Ali, but as a pointer return a question came up. I've wondered and haven't tested this but hypothetically:
>>
>> Due to that you can call structures and class members even from a pointer (transparently compared to C/C++),
> 
> It has been argued that the -> operator has not been needed for C anyway.
> 
> Interestingly, it has some value in C++ because if a type has defined operator->() (rather, for this discussion, operator.(), which does not exist in C++ today), then the following would cause confusion for types that worked like smart pointers:
> 
> class P
> {
>     /* hypothetical operator */
>     T * operator.();
>     void foo();
> };
> 
>     P p = bar();
>     p.foo(); // foo() of the pointer type or the 'pointed to type'?
> 
> D does not have that question because the dot operator may not be overloaded. (opDot() has been (will be?) deprecated.)

opDispatch lets you write the equivalent in D [1]. The 'local' member always has to take precedence over any 'remote' ones (you can hide (rename/wrap etc) the local one if you want, doing it the other way wont work).

>> does it automatically convert
>> from a pointer to a non-pointer type if the return calls for it?
> 
> No: The dot does not convert the type. The dot has different meanings on structs vs. classes. With structs, it always operates on the struct object:
> 
>     o.sizeof   // The size of the struct object
>     o.foo()    // The member of the struct object
> 
> With classes, it operates sometimes on the reference and sometimes on the referenced object:
> 
>     o.sizeof   // The size of the class reference
>     o.foo()    // The member of the class object
> 
> That's D's way of confusing on this topic.

The dot means the same thing, you just have to remember that a class reference is actually a pointer to the class instance. IOW 'o.whatever' for classes works just like 'p.whatever' does for structs.

What is confusing is the wrong reference_type-to-pointer model, but fixing it up right now is too late. Or maybe not, given the tiny amount of D code out there and the fact that only code dealing with pointers-to-classes would be affected. Such code is probably so rare that the cost could still be acceptable.

artur

[1] Well, almost - there are things like dealing with '@property' which need
    improvements. And of course 'alias this' can be used, sometimes.
August 26, 2012
On Sunday, 26 August 2012 at 15:28:17 UTC, Ali Çehreli wrote:
> On 08/26/2012 12:55 AM, Era Scarecrow wrote:

> Interestingly, it has some value in C++ because if a type has defined operator->() (rather, for this discussion, operator.(), which does not exist in C++ today), then the following would cause confusion for types that worked like smart pointers:

> D does not have that question because the dot operator may not be overloaded. (opDot() has been (will be?) deprecated.)

 Since D wouldn't ever have a need to emulate pointers (like Iterators for C++) the -> and . overloading seem moot. Some features are best not to be implemented as they would give more trouble than they're worth.

> No: The dot does not convert the type. The dot has different meanings on structs vs. classes. With structs, it always operates on the struct object:
>
>     o.sizeof   // The size of the struct object
>     o.foo()    // The member of the struct object
>
> With classes, it operates sometimes on the reference and sometimes on the referenced object:
>
>     o.sizeof   // The size of the class reference
>     o.foo()    // The member of the class object
>
> That's D's way of confusing on this topic.

 Only if o.sizeof may refer to the pointer size and not the class object.

> You meant sv:
>
>     return sv ? sv : 0;

 Ack! bad typo! Bad bad typo!

> That is still a compilation error for a statically-typed language like D. The types of sv and 0 don't match. But the line should always be like this anyway:
>
>     return sv ? *sv : 0;
>
> Because sv is always a pointer:

 Gotcha.

> > Rather than auto could ref work?
>
> You mean, 'ref' on the return type, right? For opIn_r, it better not be 'ref', because then it would be returning a reference to a local pointer:

 And here i thought it would refer the reference (from in's case) to the original object. Mmmm.

>     // Note ref return. I think this is a bug.
>     ref opIn_r(X)(X x)
>     {
>         foreach (hash; hashes)
>         {
>             auto p = x in hash;
>             if (p)
>                 return p; // <-- return a reference to the local pointer
>         }
>
>         return null;
>     }
>
> I think that is a bug but the compiler does not give a warning about returning a reference to the local pointer.

 I've actually had this problem before. Ended up having to use ref on the input and then force a pointer to get my code elsewhere to work (without copying). But that's kinda unimportant; If the compiler issues a warning than all the better now :)

> As you said, returning *x would return a copy of the value if it were a struct.

 K. Glad to get that out of the way.