> ;(= x y) implies (isa? x y)
> (isa? 42 42)
> true
>
> ;isa? also tests for class relationships:
> (isa? String Object)
> true
Is it intentional that isa? doesn't also check instance to class
relationships? I know we have instance? for that and we can manually
take the class of an object, but is there a downside to this:
(isa? 3 Integer)
true
--Steve
Interesting! This is a much-needed improvement -- the old multimethod
dispatch was Clojure's biggest wart, IMO. I look forward to testing
this.
Graham
This is a recurring issue, mostly just because of the terminology used
is confusing and inaccurate.
I'd recommend isa? be the relation between individuals / instances and
class / categories, true when the individual / instance is a member of
the class / category. Then use ako? (A Kind Of) for the relation
between classes / categories, meaning that a sub-type / sub-class
relation.
Examples:
- (isa? "some string" String) ==> true
- (isa? "other string" Object) ==> true
[everything except nil isa? Object]
- (isa? "string string" Number) ==> false
- (ako? String Object) ==> true
[again, everything except nil isa? Object]
- (ako? Integer Number) ==> true
- (ako? Number Integer) ==> false
- (isa? String Class) ==> true
- (isa? "string" Class) ==> false
- (ako? "string" String) ==> false
- (ako? String String) ==> true
[ako? is reflexive and antisymmetric]
> At this early stage, I'm open to alternative names for isa?
>
> Rich
Randall Schulz
Many, here's a simple example:
(isa? String Class)
From a category perspective the answer is no (Strings are not
Classes), from an instance perspective the answer is yes (String is an
instance of Class). Java has isAssignableFrom and instanceof for these
two purposes, and Clojure (now) has isa? and instance?.
At this early stage, I'm open to alternative names for isa?
Reading this, I wonder whether #'vector ought not be the default
dispatch function. It would encourage the use of vectors as dispatch
values, which might make it easier to add specialized methods with
varying arities. That would sort of put a bit more "multi" into
"multimethods" by default.
Just a thought,
Graham
Good points, Rich. Suggestion withdrawn.
Graham
Do you forsee this function being used much outside of the multimethod
machinery, or other meta-level code? If not, then perhaps
(derived-or-equal? ...)? It doesn't have to be terribly short if it's
infrequently used.
(is? ...) seems wrong to me -- it suggests an identity comparison.
Best,
Graham
One problem with derived? is that this relation must also hold for
equality:
(derived? 42 42)
just doesn't seem right.
I guess I still prefer isa?, but there seems to be a presumption in
the responses here that isa? is undesirable. isa? proponents if any,
should speak up,.
So the criteria is:
Must take args as per derived.
Must make sense as prefix.
Must embrace the equality relation as well.
What about is? - seems to imply the instanceof relationship less than
isa?
(is? 42 42)
(is? String Object)
(is? ::rect ::shape)
--Chris
> So the criteria is:
>
> Must take args as per derived.
> Must make sense as prefix.
> Must embrace the equality relation as well.
Based on the criteria and all the discussion I'm now in favor of kind? .
I read about Haskell kinds and I don't think there's much chance of
confusion--plus anybody who programs in Haskell has self-selected into
a group of some of the least confusable people on the planet. :-)
Regarding isa?, I think that (isa? 3 Number) being false will always
be an initial surprise to someone learning about this feature of
Clojure. At the very least an example like this should appear in the
documentation explicitly and be explained. One wouldn't have to remain
confused for long, but it doesn't fit well as English. kind? fits
better:
(kind? 3 Number) -> false (3 is not a kind of number)
(kind? Integer Number) -> true (Integer is a kind of number)
(kind? 3 3) -> true (3 is a kind of 3)
And the other examples:
(kind? String Object) -> true
(kind? String Class) -> false ; String is a Class, but it's not a
kind of Class.
I think kind? captures best the fact that the first argument must
(usually) be more than a single instance of the second argument. I
think it also works well with the equality relation: when the second
argument represents a category that includes only 1 thing, it's
natural for that one thing to be a valid representation of that kind,
type, species.
I just noticed (again) that instance? has the opposite order of
arguments. In fact, most times when I write an instance? expression, I
get the order wrong and have to fix it after. I think it's because I'm
considering (op A B) as the Clojure way of writing (A op B) so I'm
expecting "A instance (of) ? B" to be the ordering. The current
ordering is more like ((op A) B) which has a logic to it as well, just
persistently not what I expect.
I looked up Java's instanceof and found its argument ordering is the
opposite of instance?. Rich, I know you make these choices
deliberately. What's the rationale for (instance? c x) rather than
(instance? x c)? Ease of partial application?
--Steve
Excellent point. I think the fact that we're having a hard time
finding a "good name" for this function is an indication that it is
trying to do too many things.
+1 for (derived?) or (isa?) as a test of derivation only, and making
the multimethod test #(or (= %1 %2) (derived? %1 %2)).
Graham
Well, it's a brand new feature, so any usage predictions are
speculative, but I presume isa? will be used frequently at the Repl
during development in order to test dispatch value matching and
hierarchies before using them in multimethods, and afterwards as a
debugging aid.
Rich
On Tue, Jul 29, 2008 at 9:17 AM, Rich Hickey <richh...@gmail.com> wrote:
> On Jul 29, 8:29 am, "Stephen C. Gilardi" <scgila...@me.com> wrote:
>
> I agree that, being overloaded, the docs will have to specify the
> meaning, and point to instance? for the other meaning. But a
> definition stating
That would be my only request if sticking with isa? (which I think is
a good name both in terms of intent and brevity), that the docs point
to instance?.
>> I just noticed (again) that instance? has the opposite order of
>> arguments.
>> ...
>> Rich, I know you make these choices
>> deliberately. What's the rationale for (instance? c x) rather than
>> (instance? x c)? Ease of partial application?
>
> Yes, for partial application. The idea is that it is like ((op A) B)
> as you say, and that maybe someday people will stop asking for this?
> that? and the-other? predicates, so we don't have to duplicate the
> type hierarchy with ? appended. (foo? x) ==> (instance? foo x).
I had the same question, but the partial application reasoning makes
sense. Still, coming from the Java world, it doesn't matter that the
name is instance? instead of instanceof?, I still read it as the
latter and the argument ordering will trip me up again, I'm sure.
Especially now that isa? has the opposite ordering. I'm not arguing
to change it, now that I know the motivation behind it, but felt it
was worth pointing out that I'm sure this will be confusing for others
as well. Maybe it would be worth a mention in the docs that the
ordering is to enable partial application with a quick example, such
as:
user=> (def collection? (partial instance? java.util.Collection))
#'user/collection?
user=> (collection? '(1 2 3))
true
- J.
Gack! Non-types are not kinds of anything! Individual numbers (3, e.g.)
are not kinds of things. Why would one want to conflate an equivalence
relation with a type subsumption relation?
I think proper restrictions on argument types is important here.
Whatever it ends up being called, the kind? predicate should accept
only types (Class instances) as its arguments. The individual / type
predicate should accept only a Class instance as its second argument.
Inappropriate arguments should elicit IllegalArgumentException.
> ...
>
> --Steve
Randall Schulz
Except that (derive) is specifically meant to work on
non-class-instances, like keywords. So (derives?) (or whatever it's
called) clearly needs to as well.
BTW, in general the "makes partial work well" argument seems pretty weak to me.
(partial instance? Foo)
vs.
#(instance? Foo %)
I realize partial predates the #() syntax, but for discussions of
future syntax, I think #() is worth keeping in mind.
--Chouser
I missed that. The part about it being true when = is true is mostly
what I was responding to.
> So (derives?) (or whatever it's called) clearly needs to as well.
I think I'm not seeing the whole discussion. I have yet to get my copy
of my post (the one to which you replied) and I got a notice from the
Google Groups software a couple of days ago saying they were having
trouble delivering to my mailbox, so I'm afraid I may have lost some
posts.
I suppose I should go to the Web interface and read the thread...
> ...
>
> --Chouser
Randall Schulz
Nothing, nor just using the anonymous function literal #(instance?
java.util.Collection %), like Chouser suggested. This was the first
time I'd seen partial, so I was grokking it as I was writing this.
However, now I'm back in the camp that thinks instance?'s argument
order should be swapped, if possible.
- J.
I agree. I think it's a mistake to combine what are really two radically
different predicates / relations into a single function unless the name
itself discloses the hybrid nature of the test it encodes.
> ...
>
> --
> Laurent
Randall Schulz
No, your point is reasonable, IMO. For a two-argument function, the
case for partial evaluation isn't strong, especially when Clojure has
an excellent shorthand for anonymous functions -- #(instance?
java.util.Collection %) is arguably easier to read than (partial
instance? java.util.Collection).
Partials are great for functions with many arguments (or arglists of
variable length). In a language such as Haskell, where partial
evaluation is commonplace and the syntax for writing a partial is
cleaner than the syntax for an anonymous function, there are more
compelling reasons to use them for functions with only a few
arguments, IMO.
Having said all of that, I'd still vote for leaving the arguments in a
partial-evaluation-friendly order, unless there's a strong reason not
to. If nothing else, it encourages a style of coding common in
functional languages, and I think that's a good thing for Clojure
to promote.
Best,
Graham