Uniform access to a structure "member" ?

17 views
Skip to first unread message

lpetit

unread,
Jun 23, 2008, 1:56:53 AM6/23/08
to Clojure
Hello,

I was glad to see in clojure that sequences, vectors, arrays ... as
they all implement the correct interfaces, can be used with map-like
functions !

But I didn't find a generic "getter" function that would abstract
every kind of known clojure-provided structure, as well as allowing
other user defined structures to be used (by providing a java
interface to implement).

For example, I can see specific functions working for some cases : nth
for sequences, get for maps, key as function for structs.

But for the sake of function polymorphism, could'nt it be great to
also generalize the get function ?

(get '(1 2 3) 0) => 1
(get [1 2 3] 0) => 1
(get (hash-map "a" "foo" "b" "bar") "a") => "foo"
(defstruct person :name :surname)
(get (struct-map person :name "Petit" :surname "Laurent") :name) =>
"Petit"

(get #{1 2 3} 0) => Exception (a Set does not have any deterministic
way to associate a value with some other property)

==> Oh, by the way, should'nt the (get) function on maps throw an
exception if the key is not present ? There is already the (find)
funtion for getting a value whose key we do not know is present or
not.


I'm still on the learning curve of "getting" the language, so my
questions are not very "task oriented" for the moment, but this will
come !

Thanks,

--
Laurent

Rich Hickey

unread,
Jun 23, 2008, 10:51:19 AM6/23/08
to clo...@googlegroups.com
On Mon, Jun 23, 2008 at 1:56 AM, lpetit <lauren...@gmail.com> wrote:
>
> Hello,
>
> I was glad to see in clojure that sequences, vectors, arrays ... as
> they all implement the correct interfaces, can be used with map-like
> functions !
>
> But I didn't find a generic "getter" function that would abstract
> every kind of known clojure-provided structure, as well as allowing
> other user defined structures to be used (by providing a java
> interface to implement).
>
> For example, I can see specific functions working for some cases : nth
> for sequences, get for maps, key as function for structs.
>
> But for the sake of function polymorphism, could'nt it be great to
> also generalize the get function ?
>

I don't think so. These interfaces include more than just names and
logical operations, they also come with performance guarantees. In
particular the performance can be expected to be better-than-linear
unless explicitly called out.

nth support for sequences is an aberration here, and is included only
because of Lisp heritage and its utility on very short lists, as are
found when destructuring. The use of nth on non-indexed collections of
unknown size is a bad idea.

get is part of the interface of associative things. It seems to have
wide reach only because indexed collections are also associative (they
associate indexes with values, in constant time). get does work for
sets (I'm not sure what version you were using), because the pun of "a
set associates a key with itself" can also be implemented in
better-than-linear time.

There is, IMO, no equivalent logical associative notion for sequences
or lists. It's not something I would add just for completeness - not
all data structures are the same.

As far as interfaces for extension, Clojure has an extensive set of
interfaces in its Java library, and is explicitly designed with such
extension in mind, although the Java library is not documented yet. In
this case, you can extend get support to your data structure by
implementing either clojure.lang.Associative or java.util.Map.

> ==> Oh, by the way, should'nt the (get) function on maps throw an
> exception if the key is not present ? There is already the (find)
> funtion for getting a value whose key we do not know is present or
> not.
>

I don't think so. Clojure shares with CL an appreciation of functions
returning nil when they come up with nothing. It has, IMO,
substantially more utility than throwing an exception. find is more
cumbersome, as it returns an entry, not a value. As you get familiar
with Clojure, I think you'll find there are many idioms that rely on
this - using sets or maps as filters, for example.

get differs from nth in that speculative lookup in maps is quite
common, while indexes out of range are generally bugs.

Rich

lpetit

unread,
Jun 23, 2008, 12:56:05 PM6/23/08
to Clojure
On 23 juin, 16:51, "Rich Hickey" <richhic...@gmail.com> wrote:
> On Mon, Jun 23, 2008 at 1:56 AM, lpetit <laurent.pe...@gmail.com> wrote:
> > But for the sake of function polymorphism, could'nt it be great to
> > also generalize the get function ?
>
> I don't think so. These interfaces include more than just names and
> logical operations, they also come with performance guarantees. In
> particular the performance can be expected to be better-than-linear
> unless explicitly called out.
>
> nth support for sequences is an aberration here, and is included only
> because of Lisp heritage [...]

OK, I can live with that. I was just thinking that if I wanted to
create function that don't have to care on the exact nature of the
structure, and just care about the fact that they are associative,
then I will have to make a particular case for sequences/lists if I
want to enable their use by clients of my function (be it a good idea
for performance or not).

> There is, IMO, no equivalent logical associative notion for sequences
> or lists. It's not something I would add just for completeness - not
> all data structures are the same.

Please tell me where I'm wrong, but associating the start of a list/
sequence with the numerical value 0, and continuing along with 1,
2, ... for subsequent values would be something natural for lists/
sequences ?

In fact, I still have in mind some essays of Paul Graham where he
states that he begins to work with lists as basic data structures
(instead of structs, which certainly are better ideas).
But maybe I just didn't get the point. And all in all, I can live with
that ! (the non-totally polymorphic (get) function, as well as me not
getting the point everytime ! :-)).

> > ==> Oh, by the way, should'nt the (get) function on maps throw an
> > exception if the key is not present ? There is already the (find)
> > funtion for getting a value whose key we do not know is present or
> > not.
>
> I don't think so. Clojure shares with CL an appreciation of functions
> returning nil when they come up with nothing. It has, IMO,
> substantially more utility than throwing an exception. find is more
> cumbersome, as it returns an entry, not a value. As you get familiar
> with Clojure, I think you'll find there are many idioms that rely on
> this - using sets or maps as filters, for example.

That's ok for me, I think I have inverted this problem with the
problem on the consistency of nth.

> get differs from nth in that speculative lookup in maps is quite
> common, while indexes out of range are generally bugs.

OK, I understand, thanks for the explanations.

CU,

--
Laurent

Rich Hickey

unread,
Jun 23, 2008, 1:18:00 PM6/23/08
to clo...@googlegroups.com
On Mon, Jun 23, 2008 at 12:56 PM, lpetit <lauren...@gmail.com> wrote:
>
> On 23 juin, 16:51, "Rich Hickey" <richhic...@gmail.com> wrote:
>> On Mon, Jun 23, 2008 at 1:56 AM, lpetit <laurent.pe...@gmail.com> wrote:
>> > But for the sake of function polymorphism, could'nt it be great to
>> > also generalize the get function ?
>>
>> I don't think so. These interfaces include more than just names and
>> logical operations, they also come with performance guarantees. In
>> particular the performance can be expected to be better-than-linear
>> unless explicitly called out.
>>
>> nth support for sequences is an aberration here, and is included only
>> because of Lisp heritage [...]
>
> OK, I can live with that. I was just thinking that if I wanted to
> create function that don't have to care on the exact nature of the
> structure, and just care about the fact that they are associative,
> then I will have to make a particular case for sequences/lists if I
> want to enable their use by clients of my function (be it a good idea
> for performance or not).
>
>> There is, IMO, no equivalent logical associative notion for sequences
>> or lists. It's not something I would add just for completeness - not
>> all data structures are the same.
>
> Please tell me where I'm wrong, but associating the start of a list/
> sequence with the numerical value 0, and continuing along with 1,
> 2, ... for subsequent values would be something natural for lists/
> sequences ?
>

One could think of them as being associative in that way, or equally
with get finding a value and returning the seq beginning with that
value:

(get '(a b c) b) -> (b c)

My point being that any such associative behavior for sequences is
arbitrary because sequences are not inherently associative.

> In fact, I still have in mind some essays of Paul Graham where he
> states that he begins to work with lists as basic data structures
> (instead of structs, which certainly are better ideas).
> But maybe I just didn't get the point. And all in all, I can live with
> that ! (the non-totally polymorphic (get) function, as well as me not
> getting the point everytime ! :-)).
>

In Clojure, maps give you a similarly non-restrictive and malleable
data structure for brainstorming which, when you are done, you won't
have to throw away or change. I can't imagine any use for association
lists in Clojure.

Rich

lpetit

unread,
Jun 23, 2008, 4:32:54 PM6/23/08
to Clojure
OK, thank you for this in-depth understanding of the idiomatic way to
use the clojure language.

I hope to return to you with more interesting questions soon !

--
Laurent

On 23 juin, 19:18, "Rich Hickey" <richhic...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages