July 15, 2004
"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
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
> >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?
> >
> >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)
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 :)

Cool. Let me know what you think of my 5-member taxonomy of indexed access



July 15, 2004
"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
> >> 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?
> >
> > 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>)





July 15, 2004
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
July 15, 2004
"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.



July 15, 2004
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


July 15, 2004
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.
> 
>
can't you just use the typeof operator in the function "name"
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
July 15, 2004
"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
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.
> >
> >
> can't you just use the typeof operator in the function "name"
> 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 ...



July 15, 2004
"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
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...

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.


1 2 3 4
Next ›   Last »