R3 2.100.13 adds both select and find actions (datatype function methods) to the OBJECT datatype. But, we still have a decision to make and soon! Here's the situation...
Select is similar to the idiom getin. It returns the value bound to the word within the object's context:
For many years I avoided adding this usage of select, but I've recently been writing code where both the object and the selector word can optionally be NONE, and I don't want to wrap everything with extra conditional checks or all blocks. So, I caved-in and finally added it. Yell loudly if you think it's a mistake. (My inclination is that this is fine, but I'm not sure I'm as smart as I was in 2000. Maybe it is the red wine.)
The last two cases above highlight a long-standing minor issue with objects: you cannot detect the existence of a word via selection (you must use either in or the words-of function). It's not a big problem and in fact can be considered a feature because it has its uses.
However, with that in mind, find has been defined to work this way:
Here find tells you that the word is defined in the context, even though its value is NONE.
Of course, you can do roughly the same thing with the in function:
>> in obj 'b
== b
>> in obj 'c
== none
So the bigger question becomes: is there some other find feature that we may want to use on objects? For example, would it be more useful for find to search the value part of an object, as in:
>> find obj '10
== a
>> find obj "test"
== none
Please post your thoughts on this here in the comments section. Thanks.
I have concerns in this area. 'Find is one of those functions that is highly utilized and used greatly in loops over large series. Wouldn't the additional code being poured into 'find cause a performance hit? Seems we can already accomplish these tasks with a bit more code but I would rather do it with more code then to take a performance hit with 'find.
Brian Tiffin 6-Jun-2008 22:11:26
I'll add a half ditto to Paul's concern. I, for one, am going to greatly appreciate the none-transparency of FIND. It'll just save a layer of wrapper I always add (or forget until some untrapped error is triggered by some poor unfortunate user I inflict code on). This removal of wrapper test will no doubt make (I'll add a my) code faster in the general case even if the FIND native is a tad bit slower.
Re the scan of value to return the set-word!, I'd double think that if FIND was slowed in the general case. FIND REVERSE BODY-OF obj can be used for that example feature. And with the complications that would be inherent if there were duplicate values anyway. If there is no discernible slowing of the general case then it will just be another great feature of REBOL. :)
Carl Read 6-Jun-2008 23:19:21
I'd think searching the values in objects would be used much more than searching for the object words. And if used, a find/deep would also be useful for searching within values when they're series.
Jerry Tsai 7-Jun-2008 0:41:26
obj: make object! [
type: 'TEXT ; = TEXT is a value
TEXT: "OK" ; = TEXT is a word
]
find obj 'TEXT ; < == TEXT is value or word?
Robert 7-Jun-2008 3:31:32
If we can search for VALUES a block of words needs to be returned. It's not sure that only one word with the search value exists.
Anton Rolls 7-Jun-2008 13:59:24
I think FIND as just an alias of IN is worthless and I would remove it.
Much more useful is searching for values in the object.
[Returning a set of values is cool, but maybe not for FIND, perhaps "FINDS"?]
But if a single value is returned, how do we specify to skip past the previous result for our next search ?
We can't say NEXT object can we, so...
(or whatever item was found -- points to the object containing the match)
Gary Hurst 10-Jun-2008 1:07:24
This is how I have done it in the past...
But it would be nice to have this as native.
find-it: func ["Find any item in a series of objects, searchable by field name"
data "Block of data objects" search field [word!]
/any "Allows wildcards"][
forall data [
either any [
if attempt [find data/1/:field search] [return data/1]
][
if attempt [= data/1/:field search] [return data/1]
]
]
return none]
Brian Hawley 10-Jun-2008 15:00:47
Normally I would be go for consistency, but in this case the most useful behavior would be to have find search for the value and return the (bound?) key, the opposite of select. You could have map! behave the same way (without the binding). We still have in for key screening.
Oldes, your code fails if the key isn't in the object.
Gary, please no type-specific refinements to find like /in. Carl Read's suggestion of a find/deep is interesting, though you would almost certainly lose track of exactly which series, object or map in the hierarchy you found the value in.
Anton, objects and maps aren't series (or shouldn't be) so they don't have a position or index. For that matter they don't really have an innate ordering. It makes sense that the usage patterns would be different.
Paul, action functions like find are already datatype specific without any additional overhead. The implementation of find for objects has no effect on the implementation for series types.
maxim olivier-adlhoch 11-Jun-2008 3:24:34
I'll say that the find/deep idea is a great one, for all types.
and find, if it returns only one value, really should return the word, but its easy to do an object find in R2 already, like so:
my-obj: context [
a: "aye"
b: "bee"
c: "see"
]
back find third my-obj "bee"
== [b: "bee" c: "see"]
maybe this behavior could be an alternative to the previous ideas.
I guess if find just implied that the spec is searched then we woundn't need to add 'THIRD, and we could use the returned block to traverse the object.
as anton said, we already have 'IN to detect object words, so 'FIND shouldn't just be a less usefull version of 'IN