www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Get vs Test method naming convention

reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

    - operator[] (key_type key) - this returns the element for the given key, or
creates it if it does not exist. It never returns a "does-not-exist" value
    - find(key_type key) - this returns an iterator for the element, or the
end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

    - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't have
the
? postfix. I'd like to suggest a simple convention:

    - opIndex, where appropriate never returns null. Always returns the
requested
element, or throws an InvalidKeyException (or similar)
    - getXyz() - same semantics as opIndex.
    - findXyz() - tests the existence of the element, or returns null.

The alternatives to this are, IMO, far less attractive. We can either:

A. Only have the getXyz() version, which means the client code that wants to
test
existence has to have try-catch clutter
B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
overloads, which is confusing and also precludes the opIndex form.

There are two downsides to my proposed approach:

1. People might get confused. That's the reason I'm proposing that we address
this now, by adopting a common convention.
2. We can't return a null-value for built-in types. I would suggest that this
isn't a problem for most cases, since we aren't storing built-in types in most
cases. However, there are some cases where they are used, so maybe we should
also
include a hasXyz() method, which returns a boolean indicator.

Responses?
Jul 14 2004
next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Matthew wrote:
<snip>
 For D, we don't have iterators - of which more, later ... - and we 
 don't have the ? postfix. I'd like to suggest a simple convention:
 
 - opIndex, where appropriate never returns null. Always returns the 
 requested element, or throws an InvalidKeyException (or similar)
 - getXyz() - same semantics as opIndex.
 - findXyz() - tests the existence of the element, or returns null.

At the moment, associative arrays return the value or the value type's .init, which is of course null for classes. But in general, a value can itself be null, and sometimes it's useful to be able to distinguish between the two cases. But yes, I guess it can be useful to have null indicating absence of the element. But AAs versus LAs are already inconsistent here, and you could say we're stuck with this now. Guess it's a matter of remembering to documenting your class....
 The alternatives to this are, IMO, far less attractive. We can 
 either:
 
 A. Only have the getXyz() version, which means the client code that 
 wants to test existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool 
 bExists) overloads, which is confusing and also precludes the opIndex 
 form.

C. the approach you suggested further down. We ought to have an opIn. But because it's really the RHS type of such an expression that wants to control the behaviour, there are complications with naming/priority. Meanwhile, mine uses contains. Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 14 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:cd32i7$1af9$1 digitaldaemon.com...
 Matthew wrote:
 <snip>
 For D, we don't have iterators - of which more, later ... - and we
 don't have the ? postfix. I'd like to suggest a simple convention:

 - opIndex, where appropriate never returns null. Always returns the
 requested element, or throws an InvalidKeyException (or similar)
 - getXyz() - same semantics as opIndex.
 - findXyz() - tests the existence of the element, or returns null.

At the moment, associative arrays return the value or the value type's .init, which is of course null for classes. But in general, a value can itself be null, and sometimes it's useful to be able to distinguish between the two cases. But yes, I guess it can be useful to have null indicating absence of the element. But AAs versus LAs are already inconsistent here, and you could say we're stuck with this now. Guess it's a matter of remembering to documenting your class....
 The alternatives to this are, IMO, far less attractive. We can
 either:

 A. Only have the getXyz() version, which means the client code that
 wants to test existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool
 bExists) overloads, which is confusing and also precludes the opIndex
 form.

C. the approach you suggested further down. We ought to have an opIn. But because it's really the RHS type of such an expression that wants to control the behaviour, there are complications with naming/priority. Meanwhile, mine uses contains.

opIn would be really great (although it is now a part of an expression and not an operator) And having "in" work for arrays would be cool (just like it works for associative arrays), it happens sometimes that you need to check if something is in the array and i find my self rewriting something that the compiler could do instead of me. bool found=false; foreach(T t; array) { if(myElem==t)}{found =true;break;} } if(found)... It would rally nice if i could just write: if(myElem in array) instead of the above. I use contains also :)
 Stewart.

 --
 My e-mail is valid but not my primary mailbox, aside from its being the
 unfortunate victim of intensive mail-bombing at the moment.  Please keep
 replies on the 'group where everyone may benefit.

Jul 14 2004
next sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
I like opIn, but that's only useful when a given "container" can contain only
one
type of element.

I'm currently working on a mapping to D of my Open-RJ library (shortly to be
released on SF, under BSD) which is an implementation of the Record-Jar format.
(And only 5KB!)

A database contains records, and records contains fields. However, it's also
useful to be able to treat a database as a collection of fields. Hence, the
Database class allows access to Fields and/or to Records. As such, opIn (or
contains) would only work for Record (since record is the value_type of
Database). When wanting to to deduce whether a given field was in the database,
I'm suggesting I'd the findField() syntax.

I'm just as happy to call it containsField() as findField(), in fact I like that
a bit better. The point I want to discuss is that we have an identified
convention for the two forms of index/key based retrieval: return null-value on
failure, and throw-exception on failure.



"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:cd34m0$1e01$1 digitaldaemon.com...
 "Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
 news:cd32i7$1af9$1 digitaldaemon.com...
 Matthew wrote:
 <snip>
 For D, we don't have iterators - of which more, later ... - and we
 don't have the ? postfix. I'd like to suggest a simple convention:

 - opIndex, where appropriate never returns null. Always returns the
 requested element, or throws an InvalidKeyException (or similar)
 - getXyz() - same semantics as opIndex.
 - findXyz() - tests the existence of the element, or returns null.

At the moment, associative arrays return the value or the value type's .init, which is of course null for classes. But in general, a value can itself be null, and sometimes it's useful to be able to distinguish between the two cases. But yes, I guess it can be useful to have null indicating absence of the element. But AAs versus LAs are already inconsistent here, and you could say we're stuck with this now. Guess it's a matter of remembering to documenting your class....
 The alternatives to this are, IMO, far less attractive. We can
 either:

 A. Only have the getXyz() version, which means the client code that
 wants to test existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool
 bExists) overloads, which is confusing and also precludes the opIndex
 form.

C. the approach you suggested further down. We ought to have an opIn. But because it's really the RHS type of such an expression that wants to control the behaviour, there are complications with naming/priority. Meanwhile, mine uses contains.

opIn would be really great (although it is now a part of an expression and not an operator) And having "in" work for arrays would be cool (just like it works for associative arrays), it happens sometimes that you need to check if something is in the array and i find my self rewriting something that the compiler could do instead of me. bool found=false; foreach(T t; array) { if(myElem==t)}{found =true;break;} } if(found)... It would rally nice if i could just write: if(myElem in array) instead of the above. I use contains also :)
 Stewart.

 --
 My e-mail is valid but not my primary mailbox, aside from its being the
 unfortunate victim of intensive mail-bombing at the moment.  Please keep
 replies on the 'group where everyone may benefit.


Jul 14 2004
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Ivan Senji wrote:

<snip>
 opIn would be really great (although it is now a part of an expression and
 not an operator)

What do you mean by this?
 And having "in" work for arrays would be cool (just like it works for
 associative arrays), it happens sometimes that you need to check
 if something is in the array and i find my self rewriting something that the
 compiler could do instead of me.
 
 bool found=false;
 foreach(T t; array)
 {
     if(myElem==t)}{found =true;break;}
 }
 if(found)...
 
 It would rally nice if i could just write:
 if(myElem in array)
 instead of the above.

You've just contradicted yourself. In AAs, it works by checking if a _key_ is in the array. You've given a code snippet that checks if a _value_ is in the array. You are referred back to D/24177 D/24217 And anyway, that has nothing to do with the OP's question. Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 14 2004
next sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:cd3930$1lhc$1 digitaldaemon.com...
 Ivan Senji wrote:

 <snip>
 opIn would be really great (although it is now a part of an expression


 not an operator)

What do you mean by this?

I meant to say that having opIn would be great, but "in" is not an operator. RelExpression -> RelExpression in ShiftExpression It would be nice if it was an operator.
 And having "in" work for arrays would be cool (just like it works for
 associative arrays), it happens sometimes that you need to check
 if something is in the array and i find my self rewriting something that


 compiler could do instead of me.

 bool found=false;
 foreach(T t; array)
 {
     if(myElem==t)}{found =true;break;}
 }
 if(found)...

 It would rally nice if i could just write:
 if(myElem in array)
 instead of the above.

You've just contradicted yourself. In AAs, it works by checking if a

I don't think i have. You use associative arrays to store the keys, so it makes sence to check if a value of the key is in it or not. int[char[]] AA1; //this stores char[]'s And you use normal arrays to store that type: float[] normalArray; //i store a float here I might wan't to know if a certain float is in the array.
 _key_ is in the array.  You've given a code snippet that checks if a
 _value_ is in the array.

 You are referred back to

 D/24177
 D/24217

Yes i remember those posts.
char []  x = "a string";
if ( "string" in x ) puts("matched");

I agree that this makes no sence, but i don't agree that if it was defined for normal arrays that it would have to check for the index bounds. Mathew posted then:
char []  x = "a string";
 if ( ' ' in x )
   {
       puts("matched");
   }

And this is what i would like. Associative arrays are for storing the key type, and normal arrays are for storing the type of array.
 And anyway, that has nothing to do with the OP's question.

Whose question? :)
 Stewart.

 --
 My e-mail is valid but not my primary mailbox, aside from its being the
 unfortunate victim of intensive mail-bombing at the moment.  Please keep
 replies on the 'group where everyone may benefit.

Jul 14 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Ivan Senji wrote:

<snip>
 I meant to say that having opIn would be great, but "in" is not
 an operator.
 
 RelExpression -> RelExpression in ShiftExpression
 
 It would be nice if it was an operator.

Similarly AddExpression -> AddExpression + MulExpression Straight to the point please - how is in different from an operator? <snip>
 You've just contradicted yourself.  In AAs, it works by checking if a

I don't think i have. You use associative arrays to store the keys, so it makes sence to check if a value of the key is in it or not.

No. "Key" and "value" have specific meanings in this context. array[key] == value OK, so a key may have a value, but it is different from the concept of a value in an AA. For associative arrays, X in A means that there exists a Y for which A[X] == Y (well, strictly speaking that's true of elements that aren't in, but you get the idea) You're suggesting that for linear arrays, it should mean the reverse: there exists a Y for which A[Y] == X This is an inconsistency up with which plenty of us (not to mention generic programmers) will not put.
 int[char[]] AA1; //this stores char[]'s
 
 And you use normal arrays to store that type:
 float[] normalArray; //i store a float here
 
 I might wan't to know if a certain float is in the array.

Then invent a new operator with this meaning. Don't overload operators to mean completely different things. I might also "wan't" to know if a certain value occurs as a value in an AA. The new operator would cover this case just as well. <snip>
 Associative arrays are for storing the key type, and normal arrays
 are for storing the type of array.

AAs have two types declared: the key type and the value type. Normal arrays only have the value type declared.
 And anyway, that has nothing to do with the OP's question.

Whose question? :)

OP = Original Poster. The person who started the thread. Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 14 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:cd3kj2$28hd$1 digitaldaemon.com...
 Ivan Senji wrote:

 <snip>
 I meant to say that having opIn would be great, but "in" is not
 an operator.

 RelExpression -> RelExpression in ShiftExpression

 It would be nice if it was an operator.

Similarly AddExpression -> AddExpression + MulExpression Straight to the point please - how is in different from an operator?

Ignore this! I said something stupid :)
 <snip>
 You've just contradicted yourself.  In AAs, it works by checking if a

I don't think i have. You use associative arrays to store the keys, so


 makes sence to check if a value of the key is in it or not.

No. "Key" and "value" have specific meanings in this context. array[key] == value OK, so a key may have a value, but it is different from the concept of a value in an AA. For associative arrays, X in A means that there exists a Y for which A[X] == Y

I don't see it that way. To me "X in A" means: For this X there is allready an Y so that A[X]==Y So if i do: float[char[]] A; A["string1"]=3.1; A["string2"]=3.2; And normally i can test: "string1" in A == true; "bla" in A == false; We agree on this but this is the way i see normal arrays and in. float[] A; A~= 3.1; A~=3.2; 3.1 in A == true; 4.0 in A == false; This would be very usefull! I do agree that this is a little inconsistency but it is a one that makes sence.
 (well, strictly speaking that's true of elements that aren't in, but you
 get the idea)

 You're suggesting that for linear arrays, it should mean the reverse:
 there exists a Y for which

 A[Y] == X

Exactly :)
 This is an inconsistency up with which plenty of us (not to mention
 generic programmers) will not put.
 int[char[]] AA1; //this stores char[]'s

 And you use normal arrays to store that type:
 float[] normalArray; //i store a float here

 I might wan't to know if a certain float is in the array.

Then invent a new operator with this meaning. Don't overload operators to mean completely different things.

It isn't completelly different, AAs store keys, and normal arrays store values. In is for testing is an element contained in an array.
 I might also "wan't" to know if a certain value occurs as a value in an
 AA.  The new operator would cover this case just as well.

 <snip>
 Associative arrays are for storing the key type, and normal arrays
 are for storing the type of array.

AAs have two types declared: the key type and the value type. Normal arrays only have the value type declared.
 And anyway, that has nothing to do with the OP's question.

Whose question? :)

OP = Original Poster. The person who started the thread.

Thanks! I didn't know this one. We obviouslly don't agree on in and normal arrays, but we do that having opIn would be usefull for container classes?
 Stewart.

 --
 My e-mail is valid but not my primary mailbox, aside from its being the
 unfortunate victim of intensive mail-bombing at the moment.  Please keep
 replies on the 'group where everyone may benefit.

Jul 14 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Ivan Senji wrote:

<snip>
 It isn't completelly different, AAs store keys, and normal arrays store
 values. In is for testing is an element contained in an array.

AAs store values too. <snip>
 We obviouslly don't agree on in and normal arrays, but we
 do that having opIn would be usefull for container classes?

Yes, though there is a complication. Binary operators in general look first in the left-hand type to determine what to do. But in really wants to be controlled by the right-hand type. Consequently, if we kept to the usual mechanism of left.opIn(right) or, if it's not there right.opIn_r(left) then a type could define its own way of deciding if it is in a given container, and lead to confusion. If OTOH, an exception were made so that either opIn_r takes priority, or the senses of opIn and opIn_r are reversed, then it would indeed be an exception, and I'm not sure if that would be the Right Thing. The other possibility is to call it opContains, so that it's right.opContains(left) .... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 14 2004
parent Regan Heath <regan netwin.co.nz> writes:
On Wed, 14 Jul 2004 19:31:51 +0100, Stewart Gordon <smjg_1998 yahoo.com> 
wrote:

 Ivan Senji wrote:

 <snip>
 It isn't completelly different, AAs store keys, and normal arrays store
 values. In is for testing is an element contained in an array.

AAs store values too. <snip>
 We obviouslly don't agree on in and normal arrays, but we
 do that having opIn would be usefull for container classes?

Yes, though there is a complication. Binary operators in general look first in the left-hand type to determine what to do. But in really wants to be controlled by the right-hand type. Consequently, if we kept to the usual mechanism of left.opIn(right) or, if it's not there right.opIn_r(left) then a type could define its own way of deciding if it is in a given container, and lead to confusion. If OTOH, an exception were made so that either opIn_r takes priority, or the senses of opIn and opIn_r are reversed, then it would indeed be an exception, and I'm not sure if that would be the Right Thing. The other possibility is to call it opContains, so that it's right.opContains(left) ....

Or opHas :) I think changing the order of the expression using contains or has is the best soln. eg. if (arr has key) if (arr contains key) instead of if (key in arr) I don't think this can be extended to cover normal arrays as in a normal array there can be multiple identical values, this is also true for an AA, but not true for the keys of an AA which must be unique. This uniqueness is what makes this operator possible/sensible. I think for finding a value in either an AA or normal array a template find function is the solution. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 14 2004
prev sibling parent reply Andy Friesen <andy ikagames.com> writes:
Stewart Gordon wrote:
 And having "in" work for arrays would be cool (just like it works for
 associative arrays), it happens sometimes that you need to check
 if something is in the array and i find my self rewriting something 
 that the
 compiler could do instead of me.

 bool found=false;
 foreach(T t; array)
 {
     if(myElem==t)}{found =true;break;}
 }
 if(found)...

 It would rally nice if i could just write:
 if(myElem in array)
 instead of the above.

<snip> You've just contradicted yourself. In AAs, it works by checking if a _key_ is in the array. You've given a code snippet that checks if a _value_ is in the array.

It may be contradictory, but the meaning is completely clear and it's something that programmers need to do constantly. If the inconsistency really is that troublesome, D could simply define the 'in' operator solely for arrays. Programmers could instead write: char[][char[]] dict; if (x in dict.keys) { ... } // hot damn if (x in dict.values) { ... } -- andy
Jul 14 2004
parent Sean Kelly <sean f4.ca> writes:
In article <cd3mvn$2cue$2 digitaldaemon.com>, Andy Friesen says...
If the inconsistency really is that troublesome, D could simply define 
the 'in' operator solely for arrays.  Programmers could instead write:

	char[][char[]] dict;
	if (x in dict.keys) { ... } // hot damn
	if (x in dict.values) { ... }

I wouldn't mind having better support for hash sets in D. I ended up using a map just to get the speed I wanted. Maybe something like this? void[char[]] set; // char[] key and no value type Sean
Jul 14 2004
prev sibling next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...

Responses?

what on Earth is wrong with # if (a in map) # { # //... # } ?
Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:cd34as$1dct$1 digitaldaemon.com...
 In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...

Responses?

what on Earth is wrong with # if (a in map) # { # //... # } ?

Is this a genuine, considered response, or are you just seeking to waste my eye-time? I take it you feel built-in associative arrays represent the totality of associative containers we'll ever consider for D. I disagree, and am hoping to get some useful feedback in that regard.
Jul 14 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cd359e$1f32$1 digitaldaemon.com>, Matthew says...

Is this a genuine, considered response, or are you just seeking to waste my
eye-time?

Is this a genuine, considered question, or are you just in a bad mood for some reason? I assume you don't SERIOUSLY imagine that I would deliberately seek to waste your "eye-time". If you do imagine that, you must be a very paranoid individual. Why on /Earth/ would I do that? I've never even met you. Chill out, man. Go and have a cup of tea and stop taking everything so seriously.
I take it you feel built-in associative arrays represent the totality of
associative containers we'll ever consider for D.

No you don't. You just said that to be sarcastic. R-e-l-a-x. When I said:
what on Earth is wrong with

 #    if (a in map)
 #    {
 #        //...
 #    }

perhaps I should have said, what on Earth is wrong with # if (myContainer.contains(a)) # { # //... # } but it's the same difference. Now come on, be nice to me... Jill
Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:cd37j6$1j7b$1 digitaldaemon.com...
 In article <cd359e$1f32$1 digitaldaemon.com>, Matthew says...

Is this a genuine, considered response, or are you just seeking to waste my
eye-time?

Is this a genuine, considered question, or are you just in a bad mood for some reason?

Not in a bad mood. Short on time. Short on patience. Your response smacked of being half-considered, and more rejoinder for rejoinder's sake. It still seems like that now.
 I assume you don't SERIOUSLY imagine that I would deliberately seek to waste
 your "eye-time". If you do imagine that, you must be a very paranoid

 Why on /Earth/ would I do that? I've never even met you. Chill out, man. Go and
 have a cup of tea and stop taking everything so seriously.

Well, it was a sarcastic way of saying "what an ill-considered response". I guess I was being gutless in doing the former, rather than saying the latter. I've girded my loins, and told you what I think. No longer gutless smartass. Now patronising prig. Which do you prefer?
I take it you feel built-in associative arrays represent the totality of
associative containers we'll ever consider for D.

No you don't. You just said that to be sarcastic. R-e-l-a-x. When I said:
what on Earth is wrong with

 #    if (a in map)
 #    {
 #        //...
 #    }

perhaps I should have said, what on Earth is wrong with

Perhaps
 #    if (myContainer.contains(a))
 #    {
 #        //...
 #    }

 but it's the same difference. Now come on, be nice to me...

This is nice. :) But you've still jumped straight in without considering my point. The in / contains returns a boolean. That's nice, and a useful feature. But I was talking about a syntactic convention for differentiating between two different value-returning types. In one case, we want an exception to be thrown, so we can write client code to not have to care about missing elements. In the other, we want a get-existing-or-return-null semantic. I do like opIn, and I do like the contains method. But I want comment on the naming for two value-returning types. I suggested getXyz and opIndex for the get-existing-or-throw-exception type, and findXyz (could be testXyz instead) for the get-existing-or-return-null type. This is what I'm interested in everyone's thoughts about. The reason I case is that such a thing can only be a convention, not a "law", and I want to avoid the crappy naming mess that is the C++ standard library: "empty() => is_empty?", "clear() => make_empty()" !! Hence, concensus is important. Thoughts everyone?
Jul 14 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <cd389r$1kg4$1 digitaldaemon.com>, Matthew says...
The reason I case is that such a thing can only be a convention, not a "law",
and
I want to avoid the crappy naming mess that is the C++ standard library:
"empty()
=> is_empty?", "clear() => make_empty()" !!

Darn, and I like the C++ naming scheme. I suppose empty() is an odd case because it can be both a noun and a verb, but the meaning of clear() is, well, clear :) isEmpty() wouldn't be bad I suppose, though by that argument I suppose empty() would replace clear() Sean
Jul 14 2004
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd40jp$2t8p$1 digitaldaemon.com...
 In article <cd389r$1kg4$1 digitaldaemon.com>, Matthew says...
The reason I case is that such a thing can only be a convention, not a "law",


I want to avoid the crappy naming mess that is the C++ standard library:


=> is_empty?", "clear() => make_empty()" !!

Darn, and I like the C++ naming scheme. I suppose empty() is an odd case because it can be both a noun and a verb, but the meaning of clear() is, well, clear :) isEmpty() wouldn't be bad I suppose, though by that argument I

 empty() would replace clear()

In DTL, I've used isEmpty() and clear(), but steered clear (arf, arf) of empty entirely. I always - except where conforming to STL conventions - try to make methods be verbs or questions.
Jul 14 2004
prev sibling next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Matthew wrote:
 I'd like to solicit opinion on method naming conventions.
 
 In C++, std::map's entry access is via the following methods:
 
     - operator[] (key_type key) - this returns the element for the given key,
or
 creates it if it does not exist. It never returns a "does-not-exist" value
     - find(key_type key) - this returns an iterator for the element, or the
end()
 iterator if it does not exist
 
 In Ruby, we have the useful syntactic convention of ? for testing:
 
     - include?(val)
 
 For D, we don't have iterators - of which more, later ... - and we don't have
the
 ? postfix. I'd like to suggest a simple convention:
 
     - opIndex, where appropriate never returns null. Always returns the
requested
 element, or throws an InvalidKeyException (or similar)
     - getXyz() - same semantics as opIndex.
     - findXyz() - tests the existence of the element, or returns null.
 
 The alternatives to this are, IMO, far less attractive. We can either:
 
 A. Only have the getXyz() version, which means the client code that wants to
test
 existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
 overloads, which is confusing and also precludes the opIndex form.
 
 There are two downsides to my proposed approach:
 
 1. People might get confused. That's the reason I'm proposing that we address
 this now, by adopting a common convention.
 2. We can't return a null-value for built-in types. I would suggest that this
 isn't a problem for most cases, since we aren't storing built-in types in most
 cases. However, there are some cases where they are used, so maybe we should
also
 include a hasXyz() method, which returns a boolean indicator.
 
 Responses?

I think Python really nailed this one on the head. It does pretty much the same thing, but goes a hair further: get(key, default) - accepts a second argument, which is returned if the key sn't present. (this second argument defaults to None; T.init is as close to that as D gets) setdefault(key, default) - same as get(), except it also assigns the value if the key isn't present. eg: if 'key' not in dict: dict['key'] = 'default' return dict['key'] contains(key) - tests for the existence of a key, returns a boolean. -- andy
Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Andy Friesen" <andy ikagames.com> wrote in message
news:cd3muf$2cue$1 digitaldaemon.com...
 Matthew wrote:
 I'd like to solicit opinion on method naming conventions.

 In C++, std::map's entry access is via the following methods:

     - operator[] (key_type key) - this returns the element for the given key,


 creates it if it does not exist. It never returns a "does-not-exist" value
     - find(key_type key) - this returns an iterator for the element, or the


 iterator if it does not exist

 In Ruby, we have the useful syntactic convention of ? for testing:

     - include?(val)

 For D, we don't have iterators - of which more, later ... - and we don't have


 ? postfix. I'd like to suggest a simple convention:

     - opIndex, where appropriate never returns null. Always returns the


 element, or throws an InvalidKeyException (or similar)
     - getXyz() - same semantics as opIndex.
     - findXyz() - tests the existence of the element, or returns null.

 The alternatives to this are, IMO, far less attractive. We can either:

 A. Only have the getXyz() version, which means the client code that wants to


 existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
 overloads, which is confusing and also precludes the opIndex form.

 There are two downsides to my proposed approach:

 1. People might get confused. That's the reason I'm proposing that we address
 this now, by adopting a common convention.
 2. We can't return a null-value for built-in types. I would suggest that this
 isn't a problem for most cases, since we aren't storing built-in types in


 cases. However, there are some cases where they are used, so maybe we should


 include a hasXyz() method, which returns a boolean indicator.

 Responses?

I think Python really nailed this one on the head. It does pretty much the same thing, but goes a hair further: get(key, default) - accepts a second argument, which is returned if the key sn't present. (this second argument defaults to None; T.init is as close to that as D gets) setdefault(key, default) - same as get(), except it also assigns the value if the key isn't present. eg: if 'key' not in dict: dict['key'] = 'default' return dict['key'] contains(key) - tests for the existence of a key, returns a boolean.

If I understand correctly, then my criticism of this is that it prevents one from cascading [], as in Node n = doc["D"]["PrettyPrinter"]; which is a big loss, IMO, when dealing with object models over structured content. If you care only that the totality of your required structure is there, or it's not, then you want to be able to cascade instances implementing opIndex. If we have to use the get(key, default), then we can't do that.
Jul 14 2004
parent Andy Friesen <andy ikagames.com> writes:
Matthew wrote:
 If I understand correctly, then my criticism of this is that it prevents one
from
 cascading [], as in
 
     Node n = doc["D"]["PrettyPrinter"];
 
 which is a big loss, IMO, when dealing with object models over structured
 content. If you care only that the totality of your required structure is
there,
 or it's not, then you want to be able to cascade instances implementing
opIndex.
 If we have to use the get(key, default), then we can't do that.

errrr sorry. Python does precisely what you suggested with respect to opIndex, so I didn't bother to mention it. -- andy
Jul 14 2004
prev sibling next sibling parent reply Daniel Horn <hellcatv hotmail.com> writes:
I, for one, will be storing builtin types much (over 50%) of the time.
or structs :-)
I mean how many of us have not at one point or another made a map from 
int to int, or from string to int even ... it's clearly a very common 
case...and I'm not a big fan of using a class Integer to wrap an int
not sure either structs or builtins can be null when returning

you probably want the findXyz to return a pointer if it's a builtin type 
(either using specialization or else always return a pointer)

Matthew wrote:
 I'd like to solicit opinion on method naming conventions.
 
 In C++, std::map's entry access is via the following methods:
 
     - operator[] (key_type key) - this returns the element for the given key,
or
 creates it if it does not exist. It never returns a "does-not-exist" value
     - find(key_type key) - this returns an iterator for the element, or the
end()
 iterator if it does not exist
 
 In Ruby, we have the useful syntactic convention of ? for testing:
 
     - include?(val)
 
 For D, we don't have iterators - of which more, later ... - and we don't have
the
 ? postfix. I'd like to suggest a simple convention:
 
     - opIndex, where appropriate never returns null. Always returns the
requested
 element, or throws an InvalidKeyException (or similar)
     - getXyz() - same semantics as opIndex.
     - findXyz() - tests the existence of the element, or returns null.
 
 The alternatives to this are, IMO, far less attractive. We can either:
 
 A. Only have the getXyz() version, which means the client code that wants to
test
 existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
 overloads, which is confusing and also precludes the opIndex form.
 
 There are two downsides to my proposed approach:
 
 1. People might get confused. That's the reason I'm proposing that we address
 this now, by adopting a common convention.
 2. We can't return a null-value for built-in types. I would suggest that this
 isn't a problem for most cases, since we aren't storing built-in types in most
 cases. However, there are some cases where they are used, so maybe we should
also
 include a hasXyz() method, which returns a boolean indicator.
 
 Responses?
 
 

Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
Fair point

What about:

    -    value_type getXyz(key_type key) returns the requested element, or throw
InvalidKeyException
    -    bool containsXyz(key_type key) returns true/false, indicating presence
of element
    -    value_type findXyx(key_type key, value_type defaultValue) returns the
requested element, or the given default

    -    opIndex() is a synonym for getXyz where the container has only a single
value_type, or its primary value_type is obviously delineated from any secondary
value_types.

I'm pretty happy with this picture. Votes?



"Daniel Horn" <hellcatv hotmail.com> wrote in message
news:cd3qim$2iov$1 digitaldaemon.com...
 I, for one, will be storing builtin types much (over 50%) of the time.
 or structs :-)
 I mean how many of us have not at one point or another made a map from
 int to int, or from string to int even ... it's clearly a very common
 case...and I'm not a big fan of using a class Integer to wrap an int
 not sure either structs or builtins can be null when returning

 you probably want the findXyz to return a pointer if it's a builtin type
 (either using specialization or else always return a pointer)

 Matthew wrote:
 I'd like to solicit opinion on method naming conventions.

 In C++, std::map's entry access is via the following methods:

     - operator[] (key_type key) - this returns the element for the given key,


 creates it if it does not exist. It never returns a "does-not-exist" value
     - find(key_type key) - this returns an iterator for the element, or the


 iterator if it does not exist

 In Ruby, we have the useful syntactic convention of ? for testing:

     - include?(val)

 For D, we don't have iterators - of which more, later ... - and we don't have


 ? postfix. I'd like to suggest a simple convention:

     - opIndex, where appropriate never returns null. Always returns the


 element, or throws an InvalidKeyException (or similar)
     - getXyz() - same semantics as opIndex.
     - findXyz() - tests the existence of the element, or returns null.

 The alternatives to this are, IMO, far less attractive. We can either:

 A. Only have the getXyz() version, which means the client code that wants to


 existence has to have try-catch clutter
 B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
 overloads, which is confusing and also precludes the opIndex form.

 There are two downsides to my proposed approach:

 1. People might get confused. That's the reason I'm proposing that we address
 this now, by adopting a common convention.
 2. We can't return a null-value for built-in types. I would suggest that this
 isn't a problem for most cases, since we aren't storing built-in types in


 cases. However, there are some cases where they are used, so maybe we should


 include a hasXyz() method, which returns a boolean indicator.

 Responses?


Jul 14 2004
next sibling parent reply Daniel Horn <hellcatv hotmail.com> writes:
Not sure you cover all the cases... we need something that returns a 
pair with the value(or a default) and a bool

lets assume a lookup is slow
and I have a map<int,int>

what if I want each and every integer to have a valid place in my map 
(i.e. there are no garbage values for data points)
but I would like to see if that integer is in my map
and if not then I would like to insert it at that place....
how would this be accomplished with your setup?

with a STL map I'd just do a upper bound find :-)
and then insert it with that value as a hint.

another situation that this does not cover:

I'd like to see if my int is in the map (hardly likely) (any int is 
valid), and if so, then I would like to get that value. to accomplish 
this I would have to do a contains, THEN a find!
and in that case if I did the getXyz() I would get an exception 99% of 
the time--that's hardly exceptional and would likely be a fair bit 
slower than desired. I guess I could cook up some unlikely default 
value...and in the event of the default value do a contains..but that's 
the kind of code I wouldn't want to have to write each time I just wish 
to do a find.

What's wrong with returning a pointer to the desired value again? :-) 
and null if it's gone... cus memory is certain to have an unused default 
value of 0 :-)

so my proposal is:

value_type* findXyx(key_type key)
  returns the ref of requested element
that way you can modify it as well

Matthew wrote:
 Fair point
 
 What about:
 
     -    value_type getXyz(key_type key) returns the requested element, or
throw
 InvalidKeyException
     -    bool containsXyz(key_type key) returns true/false, indicating presence
 of element
     -    value_type findXyx(key_type key, value_type defaultValue) returns the
 requested element, or the given default
 
     -    opIndex() is a synonym for getXyz where the container has only a
single
 value_type, or its primary value_type is obviously delineated from any
secondary
 value_types.
 
 I'm pretty happy with this picture. Votes?
 
 
 
 "Daniel Horn" <hellcatv hotmail.com> wrote in message
 news:cd3qim$2iov$1 digitaldaemon.com...
 
I, for one, will be storing builtin types much (over 50%) of the time.
or structs :-)
I mean how many of us have not at one point or another made a map from
int to int, or from string to int even ... it's clearly a very common
case...and I'm not a big fan of using a class Integer to wrap an int
not sure either structs or builtins can be null when returning

you probably want the findXyz to return a pointer if it's a builtin type
(either using specialization or else always return a pointer)

Matthew wrote:

I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

    - operator[] (key_type key) - this returns the element for the given key,


or
creates it if it does not exist. It never returns a "does-not-exist" value
    - find(key_type key) - this returns an iterator for the element, or the


end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

    - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't have


the
? postfix. I'd like to suggest a simple convention:

    - opIndex, where appropriate never returns null. Always returns the


requested
element, or throws an InvalidKeyException (or similar)
    - getXyz() - same semantics as opIndex.
    - findXyz() - tests the existence of the element, or returns null.

The alternatives to this are, IMO, far less attractive. We can either:

A. Only have the getXyz() version, which means the client code that wants to


test
existence has to have try-catch clutter
B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
overloads, which is confusing and also precludes the opIndex form.

There are two downsides to my proposed approach:

1. People might get confused. That's the reason I'm proposing that we address
this now, by adopting a common convention.
2. We can't return a null-value for built-in types. I would suggest that this
isn't a problem for most cases, since we aren't storing built-in types in


most
cases. However, there are some cases where they are used, so maybe we should


also
include a hasXyz() method, which returns a boolean indicator.

Responses?



Jul 14 2004
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Daniel Horn" <hellcatv hotmail.com> wrote in message
news:cd48u5$c2j$1 digitaldaemon.com...
 Not sure you cover all the cases... we need something that returns a
 pair with the value(or a default) and a bool

 lets assume a lookup is slow
 and I have a map<int,int>

Not to be a pedantic fop, but isn't one of the purposes of associative containers that they're efficient at lookup?
 what if I want each and every integer to have a valid place in my map
 (i.e. there are no garbage values for data points)
 but I would like to see if that integer is in my map
 and if not then I would like to insert it at that place....
 how would this be accomplished with your setup?

 with a STL map I'd just do a upper bound find :-)
 and then insert it with that value as a hint.

 another situation that this does not cover:

 I'd like to see if my int is in the map (hardly likely) (any int is
 valid), and if so, then I would like to get that value. to accomplish
 this I would have to do a contains, THEN a find!

For this kind of containment model, there's no reason why we could not provide a getOrCreate() method.
 and in that case if I did the getXyz() I would get an exception 99% of
 the time--that's hardly exceptional and would likely be a fair bit
 slower than desired. I guess I could cook up some unlikely default
 value...and in the event of the default value do a contains..but that's
 the kind of code I wouldn't want to have to write each time I just wish
 to do a find.

Agreed. I'm seeking to reduce unnecessary function calls. Basically, I'd like all the common cases covered by a single call. But remember, I started this thread to ask about naming conventions for such things, not necessarily to debate their merits as functions. (That's not to say it's not fruitful to discuss such things, but I expect people are writing such methods anyway. Hence, it's getting the names write and consistent that I am most concerned with.)
 What's wrong with returning a pointer to the desired value again? :-)
 and null if it's gone... cus memory is certain to have an unused default
 value of 0 :-)

You'll disenfranchise anyone who's not conversant with, and a big fan of, C/C++'s pointer syntax. It simply won't be acceptable to the D community.
 so my proposal is:

 value_type* findXyx(key_type key)
   returns the ref of requested element
 that way you can modify it as well

 Matthew wrote:
 Fair point

 What about:

     -    value_type getXyz(key_type key) returns the requested element, or


 InvalidKeyException
     -    bool containsXyz(key_type key) returns true/false, indicating


 of element
     -    value_type findXyx(key_type key, value_type defaultValue) returns


 requested element, or the given default

     -    opIndex() is a synonym for getXyz where the container has only a


 value_type, or its primary value_type is obviously delineated from any


 value_types.

 I'm pretty happy with this picture. Votes?



 "Daniel Horn" <hellcatv hotmail.com> wrote in message
 news:cd3qim$2iov$1 digitaldaemon.com...

I, for one, will be storing builtin types much (over 50%) of the time.
or structs :-)
I mean how many of us have not at one point or another made a map from
int to int, or from string to int even ... it's clearly a very common
case...and I'm not a big fan of using a class Integer to wrap an int
not sure either structs or builtins can be null when returning

you probably want the findXyz to return a pointer if it's a builtin type
(either using specialization or else always return a pointer)

Matthew wrote:

I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

    - operator[] (key_type key) - this returns the element for the given




 or

creates it if it does not exist. It never returns a "does-not-exist" value
    - find(key_type key) - this returns an iterator for the element, or the


end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

    - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't




 the

? postfix. I'd like to suggest a simple convention:

    - opIndex, where appropriate never returns null. Always returns the


requested
element, or throws an InvalidKeyException (or similar)
    - getXyz() - same semantics as opIndex.
    - findXyz() - tests the existence of the element, or returns null.

The alternatives to this are, IMO, far less attractive. We can either:

A. Only have the getXyz() version, which means the client code that wants to


test
existence has to have try-catch clutter
B. Have getXyz(key_type key) and getXyz(key_type key, out bool bExists)
overloads, which is confusing and also precludes the opIndex form.

There are two downsides to my proposed approach:

1. People might get confused. That's the reason I'm proposing that we




this now, by adopting a common convention.
2. We can't return a null-value for built-in types. I would suggest that




isn't a problem for most cases, since we aren't storing built-in types in


most
cases. However, there are some cases where they are used, so maybe we should


also
include a hasXyz() method, which returns a boolean indicator.

Responses?




Jul 14 2004
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...
Fair point

What about:

    -    value_type getXyz(key_type key) returns the requested element, or throw
InvalidKeyException
    -    bool containsXyz(key_type key) returns true/false, indicating presence
of element
    -    value_type findXyx(key_type key, value_type defaultValue) returns the
requested element, or the given default

    -    opIndex() is a synonym for getXyz where the container has only a single
value_type, or its primary value_type is obviously delineated from any secondary
value_types.

I'm pretty happy with this picture. Votes?

I don't like the new findXyz semantics. The new function requires that I either set aside a potentially valid value to signal lookup failure, do two lookups (one for containsXyz and another for findXyz), or wrap getXyz in a try block. Another possibility would be to offer two versions of findXyz, one accepting a default and one returning a pointer? Sean
Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd4dqj$m1f$1 digitaldaemon.com...
 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...
Fair point

What about:

    -    value_type getXyz(key_type key) returns the requested element, or


InvalidKeyException
    -    bool containsXyz(key_type key) returns true/false, indicating


of element
    -    value_type findXyx(key_type key, value_type defaultValue) returns the
requested element, or the given default

    -    opIndex() is a synonym for getXyz where the container has only a


value_type, or its primary value_type is obviously delineated from any


value_types.

I'm pretty happy with this picture. Votes?

I don't like the new findXyz semantics. The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try block.
 Another possibility would be to offer two versions of findXyz, one accepting a
 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement? Ok, assuming that everyone's on board with testing (by opIn and/or contains() and/or containsXyz()) and getting (opIndex and/or get() and/or getXyz()), then it's finding that's the trouble. What are our requirements for finding: To be able to determine presence (testing) and retrieve the element in the case of its being present. To determine presence we must either return a boolean or sentinel value (e.g. null). Given the dichotomy between null being a good (but not perfect) sentinel for object types, and 0/NaN being a bad sentinel for built-in types, I'd now suggest that we don't do that. Hence, presence should be indicated either by return value, or by an out parameter. Retrieval can similarly be return value or out parameter. Thus, for finding, we have two options 1. Return the value, pass the presence as an out parameter value_type findXyz(key_type key, out bool bPresent); 2. Return the presence, pass the value as an out parameter bool findXyz(key_type key, out value_type value); I'd suggest here and now that neither of these are going to satisfy all circumstances. I'd further suggest, however, that we need to decide on one and stick to it. btw, considering all this, it now seems to me that the above definition of findXyz(), incorporating a default value, is quite wrong. That should be called something else, findWithDefault[Xyz](), or something less ugly. Leaving us with the following lookup "conventions": 1. Testing - opIn and/or contains() and/or containsXyz() - returns a boolean indicating presence or absence. (We might even say an int, returning the number of items matching in non-unique containers!) 2. Getting - opIndex and/or get() and/or getXyz() - always returns the requested value. Throws InvalidKeyException otherwise 3. Finding - find() or findXyz() - returns value and presence indicator to caller. 4. Defaulted Lookup - findWithDefault() or findWithDefaultXyz() (please send in better suggestions! <g> - takes a key_type and a default value_type. Returns the default if the key is not present. 5. Creating Lookup - findOrInsert() or findOrInsertXyz() - takes key_type and "new" value_type. Returns the existing one, or inserts the new one if none existing. So, how can we all live with that?
Jul 14 2004
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cd4gnr$rp0$1 digitaldaemon.com>, Matthew says...
"Sean Kelly" <sean f4.ca> wrote in message
news:cd4dqj$m1f$1 digitaldaemon.com...
 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...

 I don't like the new findXyz semantics.  The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try block.
 Another possibility would be to offer two versions of findXyz, one accepting a
 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement?

I don't have a concrete example offhand, except that I do this quite often in C++: mymap::iterator i( m.find( "key" ) ); if( i != m.end() ) { .. } Now a case could definately be made for using getXyz here, except for the cost incurred when an exception is thrown, plus the additional coding it would require: try { int i = m.getXyz( "key" ); .. } catch( KeyNotFound e ) {} I haven't quite embraced exceptions so much that I use them for this level of flow control. I would likely just ignore the getXyz call and fake it using the others.
To determine presence we must either return a boolean or sentinel value (e.g.
null). Given the dichotomy between null being a good (but not perfect) sentinel
for object types, and 0/NaN being a bad sentinel for built-in types, I'd now
suggest that we don't do that.

Well, null could be returned for built-ins as well. Always using pointers would allow for in-place modification of values. But then pointers are potentially unsafe, so it's a tough issue.
1.  Return the value, pass the presence as an out parameter

    value_type findXyz(key_type key, out bool bPresent);

2. Return the presence, pass the value as an out parameter

    bool findXyz(key_type key, out value_type value);

I'd suggest here and now that neither of these are going to satisfy all
circumstances. I'd further suggest, however, that we need to decide on one and
stick to it.

I agree. I think that it would make more sense to return the bit value. It would maintain syntactic consistency with a contains() call and allow us to find the value and check for success in a single expression.
btw, considering all this, it now seems to me that the above definition of
findXyz(), incorporating a default value, is quite wrong. That should be called
something else, findWithDefault[Xyz](), or something less ugly.

I agree. A defaulting version is great just so long as it's not the only option. (more later, I think I'm being summoned to do more vacation stuff :) Sean
Jul 14 2004
next sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd4ik2$vg7$1 digitaldaemon.com...
 In article <cd4gnr$rp0$1 digitaldaemon.com>, Matthew says...
"Sean Kelly" <sean f4.ca> wrote in message


 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...

 I don't like the new findXyz semantics.  The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try



 Another possibility would be to offer two versions of findXyz, one accepting



 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement?

I don't have a concrete example offhand, except that I do this quite often in C++: mymap::iterator i( m.find( "key" ) ); if( i != m.end() ) { .. } Now a case could definately be made for using getXyz here, except for the cost incurred when an exception is thrown, plus the additional coding it would require: try { int i = m.getXyz( "key" ); .. } catch( KeyNotFound e ) {} I haven't quite embraced exceptions so much that I use them for this level of flow control. I would likely just ignore the getXyz call and fake it using the others.

I wouldn't write a library that placed that burden on its users. Stuff like that is shit, plain and simple.
To determine presence we must either return a boolean or sentinel value (e.g.
null). Given the dichotomy between null being a good (but not perfect)


for object types, and 0/NaN being a bad sentinel for built-in types, I'd now
suggest that we don't do that.

Well, null could be returned for built-ins as well. Always using pointers

 allow for in-place modification of values.  But then pointers are potentially
 unsafe, so it's a tough issue.

1.  Return the value, pass the presence as an out parameter

    value_type findXyz(key_type key, out bool bPresent);

2. Return the presence, pass the value as an out parameter

    bool findXyz(key_type key, out value_type value);

I'd suggest here and now that neither of these are going to satisfy all
circumstances. I'd further suggest, however, that we need to decide on one and
stick to it.

I agree. I think that it would make more sense to return the bit value. It would maintain syntactic consistency with a contains() call and allow us to

 the value and check for success in a single expression.

btw, considering all this, it now seems to me that the above definition of
findXyz(), incorporating a default value, is quite wrong. That should be


something else, findWithDefault[Xyz](), or something less ugly.

I agree. A defaulting version is great just so long as it's not the only option. (more later, I think I'm being summoned to do more vacation stuff :)

Cool. Let me know what you think of my 5-member taxonomy of indexed access, in the reposted thread.
Jul 14 2004
prev sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd4ik2$vg7$1 digitaldaemon.com...
 In article <cd4gnr$rp0$1 digitaldaemon.com>, Matthew says...
"Sean Kelly" <sean f4.ca> wrote in message


 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...

 I don't like the new findXyz semantics.  The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try



 Another possibility would be to offer two versions of findXyz, one accepting



 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement?

I don't have a concrete example offhand, except that I do this quite often in C++: mymap::iterator i( m.find( "key" ) ); if( i != m.end() ) { .. } Now a case could definately be made for using getXyz here, except for the cost incurred when an exception is thrown, plus the additional coding it would require: try { int i = m.getXyz( "key" ); .. } catch( KeyNotFound e ) {} I haven't quite embraced exceptions so much that I use them for this level of flow control. I would likely just ignore the getXyz call and fake it using the others.

I wouldn't write a library that placed that burden on its users. Stuff like that is shit, plain and simple.
To determine presence we must either return a boolean or sentinel value (e.g.
null). Given the dichotomy between null being a good (but not perfect)


for object types, and 0/NaN being a bad sentinel for built-in types, I'd now
suggest that we don't do that.

Well, null could be returned for built-ins as well. Always using pointers

 allow for in-place modification of values.  But then pointers are potentially
 unsafe, so it's a tough issue.

1.  Return the value, pass the presence as an out parameter

    value_type findXyz(key_type key, out bool bPresent);

2. Return the presence, pass the value as an out parameter

    bool findXyz(key_type key, out value_type value);

I'd suggest here and now that neither of these are going to satisfy all
circumstances. I'd further suggest, however, that we need to decide on one and
stick to it.

I agree. I think that it would make more sense to return the bit value. It would maintain syntactic consistency with a contains() call and allow us to

 the value and check for success in a single expression.

btw, considering all this, it now seems to me that the above definition of
findXyz(), incorporating a default value, is quite wrong. That should be


something else, findWithDefault[Xyz](), or something less ugly.

I agree. A defaulting version is great just so long as it's not the only option. (more later, I think I'm being summoned to do more vacation stuff :)

Cool. Let me know what you think of my 5-member taxonomy of indexed access
Jul 14 2004
prev sibling next sibling parent reply Regan Heath <regan netwin.co.nz> writes:
On Thu, 15 Jul 2004 09:47:52 +1000, Matthew 
<admin stlsoft.dot.dot.dot.dot.org> wrote:
 "Sean Kelly" <sean f4.ca> wrote in message 
 news:cd4dqj$m1f$1 digitaldaemon.com...
 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...
Fair point

What about:

    -    value_type getXyz(key_type key) returns the requested 


InvalidKeyException
    -    bool containsXyz(key_type key) returns true/false, indicating


of element
    -    value_type findXyx(key_type key, value_type defaultValue) 

requested element, or the given default

    -    opIndex() is a synonym for getXyz where the container has 


value_type, or its primary value_type is obviously delineated from any


value_types.

I'm pretty happy with this picture. Votes?

I don't like the new findXyz semantics. The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two 
 lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try 
 block.
 Another possibility would be to offer two versions of findXyz, one 
 accepting a
 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement? Ok, assuming that everyone's on board with testing (by opIn and/or contains() and/or containsXyz()) and getting (opIndex and/or get() and/or getXyz()), then it's finding that's the trouble. What are our requirements for finding: To be able to determine presence (testing) and retrieve the element in the case of its being present. To determine presence we must either return a boolean or sentinel value (e.g. null). Given the dichotomy between null being a good (but not perfect) sentinel for object types, and 0/NaN being a bad sentinel for built-in types, I'd now suggest that we don't do that. Hence, presence should be indicated either by return value, or by an out parameter. Retrieval can similarly be return value or out parameter. Thus, for finding, we have two options 1. Return the value, pass the presence as an out parameter value_type findXyz(key_type key, out bool bPresent); 2. Return the presence, pass the value as an out parameter bool findXyz(key_type key, out value_type value);

I like #2, it allows this... if (findXyz("regan",value)) { } #1 would be value = findXyz("regan",r); if (r) { }
 I'd suggest here and now that neither of these are going to satisfy all
 circumstances. I'd further suggest, however, that we need to decide on 
 one and
 stick to it.

My vote is for #2 above.
 btw, considering all this, it now seems to me that the above definition 
 of
 findXyz(), incorporating a default value, is quite wrong. That should be 
 called
 something else, findWithDefault[Xyz](), or something less ugly.

True, having a default value requires being able to pass 'no default', which is the null/0/NaN problem all over again. Do we need this at all, consider: if (!findXyz("regan",value)) value = "default"; ..use value here..
 Leaving us with the following lookup "conventions":

     1. Testing - opIn and/or contains() and/or containsXyz() - returns a 
 boolean
 indicating presence or absence. (We might even say an int, returning the 
 number
 of items matching in non-unique containers!)
     2. Getting - opIndex and/or get() and/or getXyz() - always returns 
 the
 requested value. Throws InvalidKeyException otherwise
     3. Finding - find() or findXyz() - returns value and presence 
 indicator to
 caller.
     4. Defaulted Lookup - findWithDefault() or findWithDefaultXyz() 
 (please send
 in better suggestions! <g> - takes a key_type and a default value_type. 
 Returns
 the default if the key is not present.

I don't think this is necessary (see above).
     5. Creating Lookup - findOrInsert() or findOrInsertXyz() - takes 
 key_type and
 "new" value_type. Returns the existing one, or inserts the new one if 
 none
 existing.

 So, how can we all live with that?

Sounds good. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 14 2004
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Regan Heath" <regan netwin.co.nz> wrote in message
news:opsa5kr4zf5a2sq9 digitalmars.com...
 On Thu, 15 Jul 2004 09:47:52 +1000, Matthew
 <admin stlsoft.dot.dot.dot.dot.org> wrote:
 "Sean Kelly" <sean f4.ca> wrote in message
 news:cd4dqj$m1f$1 digitaldaemon.com...
 In article <cd481o$adi$4 digitaldaemon.com>, Matthew says...
Fair point

What about:

    -    value_type getXyz(key_type key) returns the requested


InvalidKeyException
    -    bool containsXyz(key_type key) returns true/false, indicating


of element
    -    value_type findXyx(key_type key, value_type defaultValue)

requested element, or the given default

    -    opIndex() is a synonym for getXyz where the container has


value_type, or its primary value_type is obviously delineated from any


value_types.

I'm pretty happy with this picture. Votes?

I don't like the new findXyz semantics. The new function requires that I

 set aside a potentially valid value to signal lookup failure, do two
 lookups
 (one for containsXyz and another for findXyz), or wrap getXyz in a try
 block.
 Another possibility would be to offer two versions of findXyz, one
 accepting a
 default and one returning a pointer?

Can you provide a quick sample of using a findXyz() that illustrates your requirement? Ok, assuming that everyone's on board with testing (by opIn and/or contains() and/or containsXyz()) and getting (opIndex and/or get() and/or getXyz()), then it's finding that's the trouble. What are our requirements for finding: To be able to determine presence (testing) and retrieve the element in the case of its being present. To determine presence we must either return a boolean or sentinel value (e.g. null). Given the dichotomy between null being a good (but not perfect) sentinel for object types, and 0/NaN being a bad sentinel for built-in types, I'd now suggest that we don't do that. Hence, presence should be indicated either by return value, or by an out parameter. Retrieval can similarly be return value or out parameter. Thus, for finding, we have two options 1. Return the value, pass the presence as an out parameter value_type findXyz(key_type key, out bool bPresent); 2. Return the presence, pass the value as an out parameter bool findXyz(key_type key, out value_type value);

I like #2, it allows this... if (findXyz("regan",value)) { } #1 would be value = findXyz("regan",r); if (r) { }
 I'd suggest here and now that neither of these are going to satisfy all
 circumstances. I'd further suggest, however, that we need to decide on
 one and
 stick to it.

My vote is for #2 above.
 btw, considering all this, it now seems to me that the above definition
 of
 findXyz(), incorporating a default value, is quite wrong. That should be
 called
 something else, findWithDefault[Xyz](), or something less ugly.

True, having a default value requires being able to pass 'no default', which is the null/0/NaN problem all over again. Do we need this at all, consider: if (!findXyz("regan",value)) value = "default"; ..use value here..
 Leaving us with the following lookup "conventions":

     1. Testing - opIn and/or contains() and/or containsXyz() - returns a
 boolean
 indicating presence or absence. (We might even say an int, returning the
 number
 of items matching in non-unique containers!)
     2. Getting - opIndex and/or get() and/or getXyz() - always returns
 the
 requested value. Throws InvalidKeyException otherwise
     3. Finding - find() or findXyz() - returns value and presence
 indicator to
 caller.
     4. Defaulted Lookup - findWithDefault() or findWithDefaultXyz()
 (please send
 in better suggestions! <g> - takes a key_type and a default value_type.
 Returns
 the default if the key is not present.

I don't think this is necessary (see above).

Ok, but remember, my purpose here is to establish naming conventions. I am not concerned with whether or not a given container should have all of the above types of methods.
     5. Creating Lookup - findOrInsert() or findOrInsertXyz() - takes
 key_type and
 "new" value_type. Returns the existing one, or inserts the new one if
 none
 existing.

 So, how can we all live with that?

Sounds good.

Cool. Unless I get strong objections to the contrary, or, heaven forfend, and opinion from big-W, I'll proceed on these lines over the next few days. (I can always search and replace later ... <g>)
Jul 14 2004
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cd4gnr$rp0$1 digitaldaemon.com>, Matthew says...
Leaving us with the following lookup "conventions":

    1. Testing - opIn and/or contains() and/or containsXyz() - returns a boolean
indicating presence or absence. (We might even say an int, returning the number
of items matching in non-unique containers!)
    2. Getting - opIndex and/or get() and/or getXyz() - always returns the
requested value. Throws InvalidKeyException otherwise
    3. Finding - find() or findXyz() - returns value and presence indicator to
caller.
    4. Defaulted Lookup - findWithDefault() or findWithDefaultXyz() (please send
in better suggestions! <g> - takes a key_type and a default value_type. Returns
the default if the key is not present.
    5. Creating Lookup - findOrInsert() or findOrInsertXyz() - takes key_type
and
"new" value_type. Returns the existing one, or inserts the new one if none
existing.

I never asked this, but what's with the Xyz bit? Why not just contains, get, etc? Otherwise... 1. Sounds good 2. Agreed... this seems consistent with (the revised version of) C++ vectors anyway. An alternative would be to have range checking done using DBC and additionally throw exceptions in the release version. 3. Yes 4. Agreed. Se could really use find() for both because of overloading rules, but perhaps a different name would be clearer? Sean
Jul 15 2004
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd6ehj$29hh$1 digitaldaemon.com...
 In article <cd4gnr$rp0$1 digitaldaemon.com>, Matthew says...
Leaving us with the following lookup "conventions":

    1. Testing - opIn and/or contains() and/or containsXyz() - returns a


indicating presence or absence. (We might even say an int, returning the


of items matching in non-unique containers!)
    2. Getting - opIndex and/or get() and/or getXyz() - always returns the
requested value. Throws InvalidKeyException otherwise
    3. Finding - find() or findXyz() - returns value and presence indicator to
caller.
    4. Defaulted Lookup - findWithDefault() or findWithDefaultXyz() (please


in better suggestions! <g> - takes a key_type and a default value_type.


the default if the key is not present.
    5. Creating Lookup - findOrInsert() or findOrInsertXyz() - takes key_type


"new" value_type. Returns the existing one, or inserts the new one if none
existing.

I never asked this, but what's with the Xyz bit? Why not just contains, get, etc? Otherwise...

Because sometimes a container might be able to provide different types of things. The Open-RJ project (have a little look at http://gregpeet.com/_orj/ for a sneak at it; it'll soon be available at openrj.org) is just such a thing. A database consists of records, which are consisted of fields. A field is a name + optional value. An example Open-RJ file would be: %% Arturius Compiler Multiplexer Processor Configuration %% Updated: 22nd June 2004 ProcessorType: Script ScriptType: Ruby ProcessorPath: ruby %% ProcessorType: Script ScriptType: Python ProcessorPath: python %% ProcessorType: Script ScriptType: Perl ProcessorPath: perl %% The value_type of the Database class is Record. So its contains(), get(), find() methods would talk Record. However, it's also possible to just deal with all the fields in the database, without considering what records they're in. So it's also got containsField(), getField(), findFiled() etc.
 1. Sounds good
 2. Agreed... this seems consistent with (the revised version of) C++ vectors
 anyway.  An alternative would be to have range checking done using DBC and
 additionally throw exceptions in the release version.

This is an interesting one. If it was C++, and the lookup was only on index (i.e. subscripting), I'd probably go for DbC and crashing, putting the onus on client code to ensure a valid index. But because we're talking generally, and might lookup by name, and might want to support docRoot["Blah"]["Waffle"] style coding, exception is necessary for some cases. IMO its better for all containers to be consistent, so I think all should throw exceptions
 3. Yes
 4. Agreed.  Se could really use find() for both because of overloading rules,
 but perhaps a different name would be clearer?

I think that's important, yes. :) Thanks for the feedback. I think we've got a pretty clear convention here.
Jul 15 2004
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...
I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

    - operator[] (key_type key) - this returns the element for the given key, or
creates it if it does not exist. It never returns a "does-not-exist" value
    - find(key_type key) - this returns an iterator for the element, or the
end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

    - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't have
the
? postfix.

Perhaps a bit off-topic, but why no iterators in D? How else are we going to operate on the contents of a binary tree? I suppose we could use foreach for such things, but that tosses the idea of C++-like algorithms, which I always kind of liked. Though I suppose such algorithms would be more difficult to use because all template arguments must be explicitly specified (the one feature of D that makes me occasionally gnash my teeth in frustration).
    - opIndex, where appropriate never returns null. Always returns the
requested
element, or throws an InvalidKeyException (or similar)

Seems reasonable, since a built-in container will throw an out of bounds error.
    - getXyz() - same semantics as opIndex.
    - findXyz() - tests the existence of the element, or returns null.

It's the returning null thing that gets me. If I've found an element and want to iterate from there, can I?
However, there are some cases where they are used, so maybe we should also
include a hasXyz() method, which returns a boolean indicator.

Would be nice. Checking for existence is very useful, and this is perhaps more concise than findXyz() == null. Sean
Jul 14 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cd413g$2u54$1 digitaldaemon.com...
 In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...
I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

    - operator[] (key_type key) - this returns the element for the given key,


creates it if it does not exist. It never returns a "does-not-exist" value
    - find(key_type key) - this returns an iterator for the element, or the


iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

    - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't have


? postfix.

Perhaps a bit off-topic, but why no iterators in D? How else are we going to operate on the contents of a binary tree? I suppose we could use foreach for such things, but that tosses the idea of C++-like algorithms, which I always kind of liked. Though I suppose such algorithms would be more difficult to use because all template arguments must be explicitly specified (the one feature of D that makes me occasionally gnash my teeth in frustration).

As I'm finding, and will want to discuss publicly soon, algorithms are seeming pretty darn near impossible without implicit instantiation. So we can create iterators quite nicely, but getting compile-time selection of type is not possible, at least not so far as I've thought about it (which, admittedly, is not terribly far). I'm going to start a discussion on this on the dtl ng in the next couple of days. For now, I want to get some basic parts of DTL moving and out there for criticism.
Jul 14 2004
parent reply Daniel Horn <hellcatv hotmail.com> writes:
Matthew wrote:
 "Sean Kelly" <sean f4.ca> wrote in message
 news:cd413g$2u54$1 digitaldaemon.com...
 
In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...

I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

   - operator[] (key_type key) - this returns the element for the given key,


or
creates it if it does not exist. It never returns a "does-not-exist" value
   - find(key_type key) - this returns an iterator for the element, or the


end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

   - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't have


the
? postfix.

Perhaps a bit off-topic, but why no iterators in D? How else are we going to operate on the contents of a binary tree? I suppose we could use foreach for such things, but that tosses the idea of C++-like algorithms, which I always kind of liked. Though I suppose such algorithms would be more difficult to use because all template arguments must be explicitly specified (the one feature of D that makes me occasionally gnash my teeth in frustration).

As I'm finding, and will want to discuss publicly soon, algorithms are seeming pretty darn near impossible without implicit instantiation. So we can create iterators quite nicely, but getting compile-time selection of type is not possible, at least not so far as I've thought about it (which, admittedly, is not terribly far). I'm going to start a discussion on this on the dtl ng in the next couple of days. For now, I want to get some basic parts of DTL moving and out there for criticism.

instead of doing sort (a.begin(),a.end()); do sort!(typeof(a.begin()),typeof(a.end())) (a.begin(),a.end()) this really sounds like a case where having a preprocessor would be nice! (gcc -E) #define sort (a,b) sort_template!(typeof(a),typeof(b))(a,b) with macros we could do autoinstantiation... this possible with mixins?...I can't think of a way
Jul 15 2004
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Daniel Horn" <hellcatv hotmail.com> wrote in message
news:cd6fh8$29s0$1 digitaldaemon.com...
 Matthew wrote:
 "Sean Kelly" <sean f4.ca> wrote in message
 news:cd413g$2u54$1 digitaldaemon.com...

In article <cd30iv$17m8$1 digitaldaemon.com>, Matthew says...

I'd like to solicit opinion on method naming conventions.

In C++, std::map's entry access is via the following methods:

   - operator[] (key_type key) - this returns the element for the given key,


or
creates it if it does not exist. It never returns a "does-not-exist" value
   - find(key_type key) - this returns an iterator for the element, or the


end()
iterator if it does not exist

In Ruby, we have the useful syntactic convention of ? for testing:

   - include?(val)

For D, we don't have iterators - of which more, later ... - and we don't




 the

? postfix.

Perhaps a bit off-topic, but why no iterators in D? How else are we going to operate on the contents of a binary tree? I suppose we could use foreach for such things, but that tosses the idea of C++-like algorithms, which I always kind of liked. Though I suppose such algorithms would be more difficult to



because all template arguments must be explicitly specified (the one feature



D that makes me occasionally gnash my teeth in frustration).

As I'm finding, and will want to discuss publicly soon, algorithms are


 pretty darn near impossible without implicit instantiation. So we can create
 iterators quite nicely, but getting compile-time selection of type is not
 possible, at least not so far as I've thought about it (which, admittedly, is


 terribly far). I'm going to start a discussion on this on the dtl ng in the


 couple of days. For now, I want to get some basic parts of DTL moving and out
 there for criticism.

instead of doing sort (a.begin(),a.end()); do sort!(typeof(a.begin()),typeof(a.end())) (a.begin(),a.end()) this really sounds like a case where having a preprocessor would be nice! (gcc -E) #define sort (a,b) sort_template!(typeof(a),typeof(b))(a,b) with macros we could do autoinstantiation... this possible with mixins?...I can't think of a way

That's an interesting one. Of course, we'd only need the one typeof, since iterators should be of the same type. I'll bear it in mind. Actually, I'm working on alternative approaches to iterators at the moment. I don't see iterators as being anywhere near as relevant in D as they are in C++. My plan is to hack away a couple more days, and then release what I have for use/criticism. Hopefully then I can enjoy the benefit of everyone's wisdom in the areas I've not explored, or have failed to explore adequately. More soon ...
Jul 15 2004