www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Lazy range of hashes?

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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?
Aug 25 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Aug 25 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Aug 26 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Aug 26 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
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.
Aug 26 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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.
Aug 25 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
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.
Aug 26 2012
prev sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
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.
Aug 26 2012