Extend integer?

Discussion of Common Lisp
wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Extend integer?

Post by wvxvw » Sun Jul 10, 2011 9:07 am

Hello, I'm looking for basically to do this:

Code: Select all

operator int () { return this->value; }
I.e. I need an object, which, although not an integer, may be used as an integer in other situations by simply using one of it's slots (it's a date object, if you need to know). When I'm trying to extend from integer class it says that integer and standard-class are incompatible. Or, better say, it wants me to add SB-MOP:VALIDATE-SUPERCLASS method to "handle" it somehow, yet I don't really understand how am I supposed to handle it :S
Thank you for any ideas, I may be doing it totally wrong, so don't hesitate to suggest a better way of doing the same thing!

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Extend integer?

Post by ramarren » Sun Jul 10, 2011 10:00 am

You can't extend classes corresponding to built in types. They only exists so that method dispatch will work on those types. Even if you could extend them by sufficiently abusing the MetaObject protocol, which I am actually not sure if it is possible, it wouldn't work anyway, because most standard functions, especially numeric ones, are type dispatched, not class dispatched. I believe this is mostly for historical reasons, although there might be efficiency concerns.

Personally I don't really like implicit conversions, especially lossy ones. Just extract the wanted integer explicitly from an object when needed, possibly using a generic extraction function.

marcoxa
Posts: 85
Joined: Thu Aug 14, 2008 6:31 pm

Re: Extend integer?

Post by marcoxa » Mon Jul 11, 2011 12:44 am

wvxvw wrote:Hello, I'm looking for basically to do this:

Code: Select all

operator int () { return this->value; }
I.e. I need an object, which, although not an integer, may be used as an integer in other situations by simply using one of it's slots (it's a date object, if you need to know). When I'm trying to extend from integer class it says that integer and standard-class are incompatible. Or, better say, it wants me to add SB-MOP:VALIDATE-SUPERCLASS method to "handle" it somehow, yet I don't really understand how am I supposed to handle it :S
Thank you for any ideas, I may be doing it totally wrong, so don't hesitate to suggest a better way of doing the same thing!
I don't understand why you need this (apart from dealing with some Java-ism). Remember that you can still do

Code: Select all

(defmethod foo ((x integer)) ...)
I.e., INTEGER is a class in CL, so you can easily use it for dispatching...

Cheers
Marco Antoniotti

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: Extend integer?

Post by wvxvw » Mon Jul 11, 2011 12:56 am

Oh, alright then. Well, I can live without it I think. Thank you for the explanation.

marcoxa: I'm making a reader/writer of AMF format (that's similar to Protobuf or JSON, but it's a binary format with references and possibility to preserve some extra metadata such as original types of objects sent, used mostly with Flash). It has Date tag, this tag may be used as value (in which case it is basically a double) or as a reference. So, when I will need to write it, I'd need to know whether two Date objects are the same thing, or do they only have the same value (this is important in Flash, because, similarly to Java it has some sort of concept of boxing / unboxing, and Date is basically a boxed integer there). So, I thought it would be nice for this particular task to mimic this behavior.

As an aside, how would I use type defined in (deftype ...) to dispatch? It seems to only accept classes, not types.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Extend integer?

Post by ramarren » Mon Jul 11, 2011 2:20 am

wvxvw wrote:As an aside, how would I use type defined in (deftype ...) to dispatch?
Usually by using TYPECASE. This obviously requires all relevant types to be listed in the dispatching form, which is why type dispatch is usually not extensible.

One reason for this distinction is that types and classes are fundamentally different, in that an object (in a general sense) can be of only one class, with some ordered inheritance list, which means that determining the order of specificity for methods is reasonably easy. On the other hand an object can be of infinite number of types without ordering relation. For example, a number 7 is at the same time of type (integer 3 9) and (integer 5 15), neither of which is more specific than the other. Which means that any order in the dispatch would have to be arbitrary, and depending on the loading order of forms is not a particularly sane idea. In TYPECASE the order is given in a single form, which is clear.

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: Extend integer?

Post by wvxvw » Mon Jul 11, 2011 4:31 am

Thank you, but I rather meant something different. I'd like, on the contrary, to help to narrow down the possible selection options. I.e. here's an example:

Code: Select all

;; amf-value-p is defined elsewhere, 
;; amf-object is also defined elsewhere and is a class with a slot called 'properties
(deftype amf-value ()
  '(satisfies amf-value-p))

;; I don't want to eventually set the value in the hash table
;; to something that I potentially won't be able to serialize later
;; so, amf-value is rather not very specific, but there are things that
;; this function won't accept, like, complex numbers for example 
(defmethod set-property ((container amf-object) (name string) value)
  (declare (type amf-value value))
  (setf (gethash name (slot-value container 'properties)) value))

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Extend integer?

Post by Paul » Mon Jul 11, 2011 5:13 am

wvxvw wrote:Thank you, but I rather meant something different. I'd like, on the contrary, to help to narrow down the possible selection options. I.e. here's an example:

Code: Select all

;; I don't want to eventually set the value in the hash table
;; to something that I potentially won't be able to serialize later
;; so, amf-value is rather not very specific, but there are things that
;; this function won't accept, like, complex numbers for example 
(defmethod set-property ((container amf-object) (name string) value)
  (declare (type amf-value value))
  (setf (gethash name (slot-value container 'properties)) value))
If you want to guarantee that, you'd be better to use (assert (amf-value-p value)) rather than the type declaration, which serves no purpose here (CMUCL turns it into a check, under some compiler settings, but other implementations won't).

(Should probably use (defmethod (setf property) (value (container amf-object) (name string)) ...), too...)

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Extend integer?

Post by ramarren » Mon Jul 11, 2011 5:14 am

The type declaration is a promise made to compiler, and, depending on set safety level, might not be checked at all. The point of such declaration is optimization, as the compiler can use type information to generate more specific code. In which case consequences are undefined if the declaration is violated, and in low safety level the entire system might crash. Although the type propagation system can't really do anything with 'satisfies' type, anyway.

A way to constrain argument types is to use the CHECK-TYPE macro, which inserts an explicit type assertion. This is run time assertions obviously, since there is no real way to statically verify types in Common Lisp for general types, although SBCL for example has some type propagation capability.

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

Re: Extend integer?

Post by wvxvw » Mon Jul 11, 2011 6:14 am

Paul: Oh, thank you... sorry, it's going to be too off topic, but I'll still ask.

Code: Select all

(defmethod (setf symbol) (...))
How would this work? I'm reading this: http://www.lispworks.com/documentation/ ... defmet.htm but it doesn't really explain it. (All it says is "If function-name is a list of the form (setf symbol), the name of the block is symbol.", but I don't understand how would I use it later). Would you be kind to give an example?
EDIT: scratch that, have figured it out. It's good to know it anyway!

Ramarren: OK, thank you... I was going to ask if one could possibly modify / extend method (and defmethod macro) to allow using types as constrains for arguments (something that in Erlang would be called `guards', but I rather stop right here, that would be a bit too advanced for me :)

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Extend integer?

Post by ramarren » Mon Jul 11, 2011 6:43 am

wvxvw wrote:How would this work?
That is just a method version of defining a SETF function. It is explained in chapter 17 of Practical Common Lisp. In short, a list of two elements like (setf name) is a valid function name, and SETF forms can expand to it as described by 5.1.2.9.
wvxvw wrote:I was going to ask if one could possibly modify / extend method (and defmethod macro) to allow using types as constrains for arguments
Well, there is something called filtered-dispatch, which allows dispatching on arbitrary predicates, but I am not sure how widely it is used, if at all. And in a narrow case of just type checking I don't see what it would add to inserting the check directly into the method, or maybe defining a :before method.

Post Reply