www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - defining "in" What is the proper way in D2?

reply Charles Hixson <charleshixsn earthlink.net> writes:
What is the proper way to define the "in" operation in D2?  I can't 
figure it out from 
http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary , and 
the source code doesn't seem to have any examples.

My current (untested) find method is:
bool	find (Key k, Node!(Key, Data) t)
{	if	(level == 0)	return	false;
	if	(k < t.key)	return	find (k, t.left);
	if (t.key < k)	return	find (k, t.right);
	return	true;
}

but I'd really rather have it be an "in" method.
Sep 11 2011
next sibling parent David Nadlinger <see klickverbot.at> writes:
On 9/11/11 10:02 PM, Charles Hixson wrote:
 What is the proper way to define the "in" operation in D2?

For containers, you typically want to use opBinaryRight: --- bool opBinaryRight(string op : "in")(ElemType e) const { return …; } --- David
Sep 11 2011
prev sibling next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson  
<charleshixsn earthlink.net> wrote:

 I can't figure it out from  
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k < key) return k in left; if (key < k) return k in right; return true; } } -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Sep 11 2011
next sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be »void opBinary(string op : "in")(Key k)«? Also, you probably want to use opBinaryRight, because opBinary hooks »if (container in key)«. David
Sep 11 2011
parent Charles Hixson <charleshixsn earthlink.net> writes:
On 09/11/2011 01:33 PM, David Nadlinger wrote:
 On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be »void opBinary(string op : "in")(Key k)«? Also, you probably want to use opBinaryRight, because opBinary hooks »if (container in key)«. David

And thanks for THIS, too. I'd just started to wonder about the order of the syntax. After all, the key is in the container, but not conversely. Charles
Sep 11 2011
prev sibling parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
 <charleshixsn earthlink.net> wrote:

 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k < key) return k in left; if (key < k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)
Sep 11 2011
next sibling parent David Nadlinger <see klickverbot.at> writes:
On 9/11/11 11:12 PM, Jonathan M Davis wrote:
 The "in" operator normally returns a pointer to the value that you're trying
 to find (and returns null if it's not there). Making it return bool may work,
 but it's going to be a problem for generic code. That's like making
 opBinary!"*" return a type different than the types being multiplied. It's just
 not how the operator is supposed to be used and could cause problems.

 - Jonathan M Davis

+1, I once ran into a bug because of which I used bool instead, but that one should be fixed since quite some time now. David
Sep 11 2011
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/11/2011 11:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net>  wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k< key) return k in left; if (key< k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code.

-1 I think the fact that "in" for AAs returns a pointer is a mistake and ugly in the first place and any generic code that relies on any container to return a raw internal pointer is flawed by itself imho.
 That's like making
 opBinary!"*" return a type different than the types being multiplied. It's just
 not how the operator is supposed to be used and could cause problems.

short a,b; static assert(!is(typeof(a * b) == short));
Sep 11 2011
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 12:21 AM, Jonathan M Davis wrote:
 On Monday, September 12, 2011 00:11:11 Timon Gehr wrote:
 On 09/11/2011 11:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net>   wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k< key) return k in left; if (key< k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code.

-1 I think the fact that "in" for AAs returns a pointer is a mistake and ugly in the first place and any generic code that relies on any container to return a raw internal pointer is flawed by itself imho.

It's an issue of efficiency. It's more efficient to grab the item once, getting null if it's not there, then it is to check if it's there and then grab it. Being a systems language, D is _very_ interested in efficiency. Keeping the pointer returned from in around for much after the call is likely to be bad code (and can certainly lead to problems), but there's nothing unsafe about the pointer in and of itself.

AAs are built-in. The optimization you describe is quite easily carried out by the compiler. And I am quite sure that in the long run, it will bite us. Sure. D is a systems language and you should probably be able to have the (unsafe) functionality. But 'in' is a predicate as in x ∈ M . It is really supposed to return a bool. I think Andrei even successfully avoids to mention the fact that it returns a pointer in TDPL. BTW: Why does the current AA implementation rely on the GC if not for avoiding dangling pointers escaped by in expressions? I think if it is the only reason, efficiency concerns cannot be a rationale for the 'feature'.
Sep 11 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 AAs are built-in. The optimization you describe is quite easily carried 
 out by the compiler. And I am quite sure that in the long run, it will 
 bite us.

With the LDC compiler if you perform an AA lookup, and after one or few lines you do it again, (because you are using an if and you are not using the pointer nature of the return value of "in AA"), LDC most times uses a single AA lookup. This little group of optimizations were added to LDC just to improve AA usage. With such simple optimizations I think 99% of times you don't need "in AA" to return a pointer. So probably returning a bool is enough. I don't think I have ever stored the return pointer of "in AA", I have used it locally, just to save one AA lookup. Bye, bearophile
Sep 11 2011
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 04:10 PM, Simen Kjaeraas wrote:
 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch> wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

This is a case of having a wrench, needing a hammer, finding a screwdriver and perform some surgery on it so that it can be used as both a screwdriver and a hammer. 'in' is a boolean predicate, except in D.
Sep 12 2011
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch> wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.
Sep 12 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 04:34 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:24:52 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.

I agree the term 'in' doesn't accurately describe the function I propose. But then again, AA doesn't provide any other means to avoid double-lookup.

The compiler could do it, because most cases of double-lookup are recognized trivially.
 I think having a different member function to do the same
 thing, and re-purposing 'in' to just return bool would be fine. This
 should be entirely possible, since AA's are now at least extendable by
 the library.

 -Steve

+1. That would be great, because it would eliminate a case of operator overloading abuse sitting right in the language's core. Also, it would open up opportunities to reuse the operator for other built-in types. if(a in [1,5,7,11]){} is so much better and DRYer than if(a==1 || a==5 || a==7 || a==11) {}
Sep 12 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 05:16 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 11:02:20 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/12/2011 04:34 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:24:52 -0400, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake
 and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.

I agree the term 'in' doesn't accurately describe the function I propose. But then again, AA doesn't provide any other means to avoid double-lookup.

The compiler could do it, because most cases of double-lookup are recognized trivially.
 I think having a different member function to do the same
 thing, and re-purposing 'in' to just return bool would be fine. This
 should be entirely possible, since AA's are now at least extendable by
 the library.

 -Steve

+1. That would be great, because it would eliminate a case of operator overloading abuse sitting right in the language's core. Also, it would open up opportunities to reuse the operator for other built-in types. if(a in [1,5,7,11]){} is so much better and DRYer than if(a==1 || a==5 || a==7 || a==11) {}

That still would need special treatment, because in should be fast (O(lgn) or better), and in on any array is O(n).

O(n) is just fine, because that is the fastest way of searching an arbitrary array.
 I'd say the array had to be a literal, or guaranteed sorted to support
 in. I'm not sure that's a great thing.

 But in order to do all this, we have to consider that a *lot* of code
 relies on a in AA returning a pointer.

What code? I think many people don't notice that it returns a pointer, because they expect it to return bool.
 I almost think it's too late to make that kind of change (have a in AA
 return bool instead of a pointer).

 One more point: it's technically not abuse, since a in AA does evaluate
 to a bool value meaning "a is in the AA". It's overloading :)

 -Steve

auto foo(){ auto x=a in aa; return x; }
Sep 12 2011
prev sibling parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 09/11/2011 02:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net>  wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false;


From: Charles Hixson<charleshixsn earthlink.net> Newsgroups: digitalmars.D.learn Subject: Re: defining "in" What is the proper way in D2? Date: Sun, 11 Sep 2011 14:09:57 -0700 Organization: Digital Mars Lines: 15 Message-ID:<j4j83k$ree$1 digitalmars.com> References:<j4j45h$iti$1 digitalmars.com> <op.v1nu0fdrtuzx1w cybershadow.mshome.net> <j4j5uq$m8n$1 digitalmars.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: digitalmars.com 1315775412 28110 66.245.57.66 (11 Sep 2011 21:10:12 GMT) X-Complaints-To: usenet digitalmars.com NNTP-Posting-Date: Sun, 11 Sep 2011 21:10:12 +0000 (UTC) User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.2.21) Gecko/20110831 Iceowl/1.0b2 Icedove/3.1.13 In-Reply-To:<j4j5uq$m8n$1 digitalmars.com> Xref: digitalmars.com digitalmars.D.learn:29434 On 09/11/2011 01:33 PM, David Nadlinger wrote:
 On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be »void opBinary(string op : "in")(Key k)«? Also, you probably want to use opBinaryRight, because opBinary hooks »if (container in key)«. David

And thanks for THIS, too. I'd just started to wonder about the order of the syntax. After all, the key is in the container, but not conversely.
 if (k<  key) return k in left;
 if (key<  k) return k in right;
 return true;
 }
 }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code. That's like making opBinary!"*" return a type different than the types being multiplied. It's just not how the operator is supposed to be used and could cause problems. - Jonathan M Davis

OK, but what if the container is supposed to be opaque to external observers, but you still want to be able to tell whether it contains a particular item? Doesn't returning a pointer violate encapsulation? Also, the compiler complained about the declaration, causing me to currently substitute, thus: // bool opBinaryRight!("in")(Key k) bool opBinaryRight(string op)(Key k) if (op == "in") I swiped that code from std.container.d (which also returns a bool). As what I'm doing is pretty much like a standard container, this seemed like a reasonable place to look. I sure hope that this doesn't mean I need to instantiate every use of in. If that's the case I might be better off just staying with find.
Sep 11 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 12:28 AM, Charles Hixson wrote:
 On 09/11/2011 02:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net> wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false;


From: Charles Hixson<charleshixsn earthlink.net> Newsgroups: digitalmars.D.learn Subject: Re: defining "in" What is the proper way in D2? Date: Sun, 11 Sep 2011 14:09:57 -0700 Organization: Digital Mars Lines: 15 Message-ID:<j4j83k$ree$1 digitalmars.com> References:<j4j45h$iti$1 digitalmars.com> <op.v1nu0fdrtuzx1w cybershadow.mshome.net> <j4j5uq$m8n$1 digitalmars.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: digitalmars.com 1315775412 28110 66.245.57.66 (11 Sep 2011 21:10:12 GMT) X-Complaints-To: usenet digitalmars.com NNTP-Posting-Date: Sun, 11 Sep 2011 21:10:12 +0000 (UTC) User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.2.21) Gecko/20110831 Iceowl/1.0b2 Icedove/3.1.13 In-Reply-To:<j4j5uq$m8n$1 digitalmars.com> Xref: digitalmars.com digitalmars.D.learn:29434 On 09/11/2011 01:33 PM, David Nadlinger wrote:
 On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be »void opBinary(string op : "in")(Key k)«? Also, you probably want to use opBinaryRight, because opBinary hooks »if (container in key)«. David

And thanks for THIS, too. I'd just started to wonder about the order of the syntax. After all, the key is in the container, but not conversely.
 if (k< key) return k in left;
 if (key< k) return k in right;
 return true;
 }
 }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code. That's like making opBinary!"*" return a type different than the types being multiplied. It's just not how the operator is supposed to be used and could cause problems. - Jonathan M Davis

OK, but what if the container is supposed to be opaque to external observers, but you still want to be able to tell whether it contains a particular item? Doesn't returning a pointer violate encapsulation? Also, the compiler complained about the declaration, causing me to currently substitute, thus: // bool opBinaryRight!("in")(Key k)

That is not valid syntax and probably will never be.
 bool opBinaryRight(string op)(Key k) if (op == "in")

 I swiped that code from std.container.d (which also returns a bool). As
 what I'm doing is pretty much like a standard container, this seemed
 like a reasonable place to look.

I agree.
 I sure hope that this doesn't mean I
 need to instantiate every use of in. If that's the case I might be
 better off just staying with find.

How do you mean, instantiate it?
Sep 11 2011
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 09/11/2011 04:07 PM, Timon Gehr wrote:
 On 09/12/2011 12:28 AM, Charles Hixson wrote:
 On 09/11/2011 02:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net> wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false;


From: Charles Hixson<charleshixsn earthlink.net> Newsgroups: digitalmars.D.learn Subject: Re: defining "in" What is the proper way in D2? Date: Sun, 11 Sep 2011 14:09:57 -0700 Organization: Digital Mars Lines: 15 Message-ID:<j4j83k$ree$1 digitalmars.com> References:<j4j45h$iti$1 digitalmars.com> <op.v1nu0fdrtuzx1w cybershadow.mshome.net> <j4j5uq$m8n$1 digitalmars.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: digitalmars.com 1315775412 28110 66.245.57.66 (11 Sep 2011 21:10:12 GMT) X-Complaints-To: usenet digitalmars.com NNTP-Posting-Date: Sun, 11 Sep 2011 21:10:12 +0000 (UTC) User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.2.21) Gecko/20110831 Iceowl/1.0b2 Icedove/3.1.13 In-Reply-To:<j4j5uq$m8n$1 digitalmars.com> Xref: digitalmars.com digitalmars.D.learn:29434 On 09/11/2011 01:33 PM, David Nadlinger wrote:
 On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be »void opBinary(string op : "in")(Key k)«? Also, you probably want to use opBinaryRight, because opBinary hooks »if (container in key)«. David

And thanks for THIS, too. I'd just started to wonder about the order of the syntax. After all, the key is in the container, but not conversely.
 if (k< key) return k in left;
 if (key< k) return k in right;
 return true;
 }
 }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code. That's like making opBinary!"*" return a type different than the types being multiplied. It's just not how the operator is supposed to be used and could cause problems. - Jonathan M Davis

OK, but what if the container is supposed to be opaque to external observers, but you still want to be able to tell whether it contains a particular item? Doesn't returning a pointer violate encapsulation? Also, the compiler complained about the declaration, causing me to currently substitute, thus: // bool opBinaryRight!("in")(Key k)

That is not valid syntax and probably will never be.
 bool opBinaryRight(string op)(Key k) if (op == "in")

 I swiped that code from std.container.d (which also returns a bool). As
 what I'm doing is pretty much like a standard container, this seemed
 like a reasonable place to look.

I agree.
 I sure hope that this doesn't mean I
 need to instantiate every use of in. If that's the case I might be
 better off just staying with find.

How do you mean, instantiate it?

Template syntax doesn't make any sense to me yet. I'm just copying examples and adapting them with a cut and try and see what works and what doesn't. More failures than successes. OTOH, it does seem better than C++ template syntax, but that's VERY faint praise indeed.
Sep 11 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/12/2011 02:53 AM, Charles Hixson wrote:
 On 09/11/2011 04:07 PM, Timon Gehr wrote:
 How do you mean, instantiate it?

Template syntax doesn't make any sense to me yet. I'm just copying examples and adapting them with a cut and try and see what works and what doesn't. More failures than successes. OTOH, it does seem better than C++ template syntax, but that's VERY faint praise indeed.

You can explicitly instantiate it like this: container.opBinaryRight!"in"(elem); but you should be able to write elem in container instead, which is the same thing.
Sep 11 2011
parent Charles Hixson <charleshixsn earthlink.net> writes:
On 09/11/2011 06:02 PM, Timon Gehr wrote:
 On 09/12/2011 02:53 AM, Charles Hixson wrote:
 On 09/11/2011 04:07 PM, Timon Gehr wrote:
 How do you mean, instantiate it?

Template syntax doesn't make any sense to me yet. I'm just copying examples and adapting them with a cut and try and see what works and what doesn't. More failures than successes. OTOH, it does seem better than C++ template syntax, but that's VERY faint praise indeed.

You can explicitly instantiate it like this: container.opBinaryRight!"in"(elem); but you should be able to write elem in container instead, which is the same thing.

Thanks, both for the reassurance, and for the alternate syntax.
Sep 11 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
 
 <charleshixsn earthlink.net> wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k < key) return k in left; if (key < k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code. That's like making opBinary!"*" return a type different than the types being multiplied. It's just not how the operator is supposed to be used and could cause problems. - Jonathan M Davis
Sep 11 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 12, 2011 00:11:11 Timon Gehr wrote:
 On 09/11/2011 11:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
 
 <charleshixsn earthlink.net>  wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k< key) return k in left; if (key< k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code.

-1 I think the fact that "in" for AAs returns a pointer is a mistake and ugly in the first place and any generic code that relies on any container to return a raw internal pointer is flawed by itself imho.

It's an issue of efficiency. It's more efficient to grab the item once, getting null if it's not there, then it is to check if it's there and then grab it. Being a systems language, D is _very_ interested in efficiency. Keeping the pointer returned from in around for much after the call is likely to be bad code (and can certainly lead to problems), but there's nothing unsafe about the pointer in and of itself.
 That's like making
 opBinary!"*" return a type different than the types being multiplied.
 It's just not how the operator is supposed to be used and could cause
 problems.

static assert(!is(typeof(a * b) == short));

Those are primitive types, not user-defined types. They are also effectively derived types in terms of how they function. There's a big difference between returning a derived type and returning a completely different type. - Jonathan M Davis
Sep 11 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 11, 2011 15:28:38 Charles Hixson wrote:
 On 09/11/2011 02:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
=20
 <charleshixsn earthlink.net>  wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary=





=20
 // I assume your data structure looks like this
 class Node(Key, Data)
 {
 Key k;
 Node!(Key, Data) left, right;
 int level;
 // ...
=20
 void opBinary!("in")(Key k)
 {
 if (level =3D=3D 0) return false;


Path: digitalmars.com!not-for-mail From: Charles Hixson<charleshixsn earthlink.net> Newsgroups: digitalmars.D.learn Subject: Re: defining "in" What is the proper way in D2? Date: Sun, 11 Sep 2011 14:09:57 -0700 Organization: Digital Mars Lines: 15 Message-ID:<j4j83k$ree$1 digitalmars.com> References:<j4j45h$iti$1 digitalmars.com>=20 <op.v1nu0fdrtuzx1w cybershadow.mshome.net>=20 <j4j5uq$m8n$1 digitalmars.com> Mime-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8; format=3Dflowed Content-Transfer-Encoding: 8bit X-Trace: digitalmars.com 1315775412 28110 66.245.57.66 (11 Sep 2011=


 21:10:12 GMT) X-Complaints-To: usenet digitalmars.com
 NNTP-Posting-Date: Sun, 11 Sep 2011 21:10:12 +0000 (UTC)
 User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US;
 rv:1.9.2.21) Gecko/20110831 Iceowl/1.0b2 Icedove/3.1.13
 In-Reply-To:<j4j5uq$m8n$1 digitalmars.com>
 Xref: digitalmars.com digitalmars.D.learn:29434
=20
 On 09/11/2011 01:33 PM, David Nadlinger wrote:
 On 9/11/11 10:25 PM, Vladimir Panteleev wrote:
 void opBinary!("in")(Key k)

Shouldn't that be =C2=BBvoid opBinary(string op : "in")(Key k)=C2=AB=



 probably want to use opBinaryRight, because opBinary hooks =C2=BBi=



 (container in key)=C2=AB.
=20
 David

And thanks for THIS, too. I'd just started to wonder about the ord=


 the syntax.  After all, the key is in the container, but not conver=


=20
 if (k<  key) return k in left;
 if (key<  k) return k in right;
 return true;
 }
 }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out fro=



 the
 docs.
=20
 And, yeah.  That's what it looks like.  My find code was wrong,
 because
 it should have referenced the node, so what I need to do is move t=



 cod
 into the node class.  But it was the syntax of defining the opBina=



 specialization that was hanging me up.  (For some reason I have a =



 time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you'=


 trying to find (and returns null if it's not there). Making it retu=


 bool may work, but it's going to be a problem for generic code. Tha=


 like making opBinary!"*" return a type different than the types bei=


 multiplied. It's just not how the operator is supposed to be used a=


 could cause problems.
=20
 - Jonathan M Davis

OK, but what if the container is supposed to be opaque to external observers, but you still want to be able to tell whether it contains =

 particular item?  Doesn't returning a pointer violate encapsulation?

Yes and no. It does provide direct access to an element in the containe= r,=20 which could cause issues if they keep the pointer around (just like wit= h any=20 iterator or range which has been invalidated by a container being alter= ed).=20 But if you're looking to stop the element from being altered, all you'd= have=20 to do is make it a pointer to const.
 Also, the compiler complained about the declaration, causing me to
 currently substitute, thus:
=20
 // bool opBinaryRight!("in")(Key k)
     bool opBinaryRight(string op)(Key k) if (op =3D=3D "in")
=20
 I swiped that code from std.container.d  (which also returns a bool).=

 As what I'm doing is pretty much like a standard container, this seem=

 like a reasonable place to look.  I sure hope that this doesn't mean =

 need to instantiate every use of in.  If that's the case I might be
 better off just staying with find.

I'm a bit surprised that std.container would have it returning bool, bu= t that=20 would work for any case where you're just checking for existence. It _i= s_=20 inefficient in many cases though, and is not great design IMHO. It may = mean that=20 templated code is ultimately going to have to use static ifs or templat= e=20 constraints to check where in returns a pointer, but the value of in is= =20 certainly reduced (albeit not eliminated) when it returns bool. As for template instantiations, you get a new template instantiation fo= r every=20 type you try and instantiate a template with a new set of template argu= ments.=20 If the only argument to opBinaryRight is the string for the operator, t= hen=20 it's only going to be instantiated once per operator. As for sticking with find, you can't implement in such that it's at lea= st as=20 efficient as searching in balance binary tree (O(log n) I believe), the= n you=20 shouldn't implement n. Ideally, it would be O(1), but that's obviously = not=20 always possible. Still, in really needs to be more efficient than find,= or it=20 shouldn't be there. But you shouldn't be having to use find just becaus= e of=20 template bloat. - Jonathan M Davis
Sep 11 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 12, 2011 01:04:39 Timon Gehr wrote:
 On 09/12/2011 12:21 AM, Jonathan M Davis wrote:
 On Monday, September 12, 2011 00:11:11 Timon Gehr wrote:
 On 09/11/2011 11:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
=20
 <charleshixsn earthlink.net>   wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Bina=







 ry

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... =20 void opBinary!("in")(Key k) { if (level =3D=3D 0) return false; if (k< key) return k in left; if (key< k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. =20 And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move=





 the
 cod
 into the node class.  But it was the syntax of defining the
 opBinary
 specialization that was hanging me up.  (For some reason I have =





 hard
 time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code.

-1 =20 I think the fact that "in" for AAs returns a pointer is a mistake =



 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imh=



=20
 It's an issue of efficiency. It's more efficient to grab the item o=


 getting null if it's not there, then it is to check if it's there a=


 then grab it. Being a systems language, D is _very_ interested in
 efficiency. Keeping the pointer returned from in around for much af=


 the call is likely to be bad code (and can certainly lead to proble=


 but there's nothing unsafe about the pointer in and of itself.

AAs are built-in. The optimization you describe is quite easily carri=

 out by the compiler. And I am quite sure that in the long run, it wil=

 bite us.
=20
 Sure. D is a systems language and you should probably be able to have=

 the (unsafe) functionality. But 'in' is a predicate as in x =E2=88=88=

 really supposed to return a bool. I think Andrei even successfully
 avoids to mention the fact that it returns a pointer in TDPL.
=20
=20
 BTW: Why does the current AA implementation rely on the GC if not for=

 avoiding dangling pointers escaped by in expressions? I think if it i=

 the only reason, efficiency concerns cannot be a rationale for the
 'feature'.

It is no more dangerous than keeping an iterator or range around after = its=20 been invalidated. In fact, it's _exactly_ the same thing. And there's n= o way=20 that you're going to get rid of that issue in an efficient manner. That= 's why=20 std.container has the stable* functions. Pointers are allowed in SafeD = and are=20 perfectly safe. It's stuff like pointer arithmetic which is unsafe and=20= disallowed in SafeD. Yes, there are issues if you keep the pointer around after the containe= r has=20 been altered, but ranges have exactly the same issue. It's a known and=20= accepted problem. The solution is to just not keep the pointer around. = If a=20 programmer keeps such a pointer aronud (or keeps a range around after a= ltering=20 a container with a non-stable* function), then they're risking buggy co= de.=20 That doesn't mean that the feature is a bad idea. - Jonathan M Davis
Sep 11 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 11 Sep 2011 18:11:11 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/11/2011 11:12 PM, Jonathan M Davis wrote:
 On Sunday, September 11, 2011 14:00:55 Charles Hixson wrote:
 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson

 <charleshixsn earthlink.net>  wrote:
 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k< key) return k in left; if (key< k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs. And, yeah. That's what it looks like. My find code was wrong, because it should have referenced the node, so what I need to do is move the cod into the node class. But it was the syntax of defining the opBinary specialization that was hanging me up. (For some reason I have a hard time wrapping my mind around template code.)

The "in" operator normally returns a pointer to the value that you're trying to find (and returns null if it's not there). Making it return bool may work, but it's going to be a problem for generic code.

-1 I think the fact that "in" for AAs returns a pointer is a mistake and ugly in the first place and any generic code that relies on any container to return a raw internal pointer is flawed by itself imho.

That reminds me, I should write opIn for dcollections maps. It will return a cursor (not a pointer). Hm... probably have to overload cursor.opStar and opCast(bool) at that point too for the sake of generic code... -Steve
Sep 12 2011
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch> wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and  
 ugly in the first place and any generic code that relies on any  
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer. -- Simen
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas  
<simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch> wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and  
 ugly in the first place and any generic code that relies on any  
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage. I think the correct return type for that should be a cursor (i.e. a single-element range which can be used to refer to that element at a later time). This allows even more functionality, such as removing the element, or referring to both the key and value. -Steve
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 10:24:52 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch>  
 wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.

I agree the term 'in' doesn't accurately describe the function I propose. But then again, AA doesn't provide any other means to avoid double-lookup. I think having a different member function to do the same thing, and re-purposing 'in' to just return bool would be fine. This should be entirely possible, since AA's are now at least extendable by the library. -Steve
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 11:02:20 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/12/2011 04:34 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:24:52 -0400, Timon Gehr <timon.gehr gmx.ch>  
 wrote:

 On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake  
 and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.

I agree the term 'in' doesn't accurately describe the function I propose. But then again, AA doesn't provide any other means to avoid double-lookup.

The compiler could do it, because most cases of double-lookup are recognized trivially.
 I think having a different member function to do the same
 thing, and re-purposing 'in' to just return bool would be fine. This
 should be entirely possible, since AA's are now at least extendable by
 the library.

 -Steve

+1. That would be great, because it would eliminate a case of operator overloading abuse sitting right in the language's core. Also, it would open up opportunities to reuse the operator for other built-in types. if(a in [1,5,7,11]){} is so much better and DRYer than if(a==1 || a==5 || a==7 || a==11) {}

That still would need special treatment, because in should be fast (O(lgn) or better), and in on any array is O(n). I'd say the array had to be a literal, or guaranteed sorted to support in. I'm not sure that's a great thing. But in order to do all this, we have to consider that a *lot* of code relies on a in AA returning a pointer. I almost think it's too late to make that kind of change (have a in AA return bool instead of a pointer). One more point: it's technically not abuse, since a in AA does evaluate to a bool value meaning "a is in the AA". It's overloading :) -Steve
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 11:23:36 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/12/2011 05:16 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 11:02:20 -0400, Timon Gehr <timon.gehr gmx.ch>  
 wrote:

 On 09/12/2011 04:34 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:24:52 -0400, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 On 09/12/2011 04:17 PM, Steven Schveighoffer wrote:
 On Mon, 12 Sep 2011 10:10:35 -0400, Simen Kjaeraas
 <simen.kjaras gmail.com> wrote:

 On Mon, 12 Sep 2011 00:11:11 +0200, Timon Gehr <timon.gehr gmx.ch>
 wrote:

 I think the fact that "in" for AAs returns a pointer is a mistake
 and
 ugly in the first place and any generic code that relies on any
 container to return a raw internal pointer is flawed by itself  
 imho.

If D had a Nullable struct, that would likely be a much better return type for 'in'. The thing is, we do have a nullable!T type: T*. This is simply a case of having a wrench and needing a hammer.

No, the advantage of using a pointer is, you can change the value without incurring another lookup. A nullable struct does not have that advantage.

A decent compiler has that advantage without requiring programmers to abuse the 'in' operator.
 I think the correct return type for that should be a cursor (i.e. a
 single-element range which can be used to refer to that element at a
 later time). This allows even more functionality, such as removing  
 the
 element, or referring to both the key and value.

The correct return type for 'in' is bool. But the functionality you propose could be quite useful indeed.

I agree the term 'in' doesn't accurately describe the function I propose. But then again, AA doesn't provide any other means to avoid double-lookup.

The compiler could do it, because most cases of double-lookup are recognized trivially.
 I think having a different member function to do the same
 thing, and re-purposing 'in' to just return bool would be fine. This
 should be entirely possible, since AA's are now at least extendable by
 the library.

 -Steve

+1. That would be great, because it would eliminate a case of operator overloading abuse sitting right in the language's core. Also, it would open up opportunities to reuse the operator for other built-in types. if(a in [1,5,7,11]){} is so much better and DRYer than if(a==1 || a==5 || a==7 || a==11) {}

That still would need special treatment, because in should be fast (O(lgn) or better), and in on any array is O(n).

O(n) is just fine, because that is the fastest way of searching an arbitrary array.

No it's not fine. Even if you think it is, you will never get this past Andrei (or me). a in b should be fast, it's already associated with efficiency.
 I'd say the array had to be a literal, or guaranteed sorted to support
 in. I'm not sure that's a great thing.

 But in order to do all this, we have to consider that a *lot* of code
 relies on a in AA returning a pointer.

What code? I think many people don't notice that it returns a pointer, because they expect it to return bool.

I use it whenever I use AA's to avoid double lookup. Look in any code that uses AA's and cares about efficiency: if(auto v = a in b) { *v = newval; } else { b[a] = newval; }
 I almost think it's too late to make that kind of change (have a in AA
 return bool instead of a pointer).

 One more point: it's technically not abuse, since a in AA does evaluate
 to a bool value meaning "a is in the AA". It's overloading :)

 -Steve

auto foo(){ auto x=a in aa; return x; }

if(foo()) works just fine ;) -Steve
Sep 12 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, September 12, 2011 17:23:36 Timon Gehr wrote:
 On 09/12/2011 05:16 PM, Steven Schveighoffer wrote:
 I'd say the array had to be a literal, or guaranteed sorted to support
 in. I'm not sure that's a great thing.
 
 But in order to do all this, we have to consider that a *lot* of code
 relies on a in AA returning a pointer.

What code? I think many people don't notice that it returns a pointer, because they expect it to return bool.

The documentation is quite clear that in returns a pointer which is null if the item isn't there, so there's going to be code that relies on that fact. - Jonathan M Davis
Sep 12 2011
prev sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Mon, 12 Sep 2011 00:00:55 +0300, Charles Hixson  
<charleshixsn earthlink.net> wrote:

 On 09/11/2011 01:25 PM, Vladimir Panteleev wrote:
 On Sun, 11 Sep 2011 23:02:37 +0300, Charles Hixson
 <charleshixsn earthlink.net> wrote:

 I can't figure it out from
 http://www.digitalmars.com/d/2.0/operatoroverloading.html#Binary

// I assume your data structure looks like this class Node(Key, Data) { Key k; Node!(Key, Data) left, right; int level; // ... void opBinary!("in")(Key k) { if (level == 0) return false; if (k < key) return k in left; if (key < k) return k in right; return true; } }

VOID?? I'm going to presume that this should have been bool. Otherwise, thanks. That was they syntax I couldn't figure out from the docs.

Sorry. Shouldn't have tried this while tired. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Sep 12 2011