From: Matthew X. Economou
Subject: Enforcing type specifications
Date:
Message-ID: <uabz7a0ap.fsf@irtnog.org>
Are type specifications in Common Lisp intended to enforce constraints
on the type of a place's value (whether that place is a slot, a
function's argument, a lexical or dynamic binding, etc.), or are type
specs used only for optimization (if those declarations are used at
all)? For example, if I define the following class in clisp, I can
assign values to the slot that violate the type specification:
[1]> (defclass test ()
((mode :type (member :one :two :three)
:initform :one)))
#<STANDARD-CLASS TEST>
[2]> (setq test-instance (make-instance 'test))
#<TEST #x10202FF5>
[3]> (slot-value test-instance 'mode)
:ONE
[4]> (setf (slot-value test-instance 'mode) 1)
1
[5]> (slot-value test-instance 'mode)
1
(I experienced identical behavior in SBCL and CMUCL.) I would have
expected that, at the default safety and optimization settings, an
implementation would signal a type error when a value doesn't match a
place's type specification.
Could a implementation enforce type specifications and still be
conforming? (From this behavior, I take it that portable code cannot
rely on type specifications and must include explicit type checks as
needed.)
In the case of classes and the slot-value accessor, how could one
portably augment slot-value such that it would include strict type
checks, or is one forced to create their own accessor function which
would include an explicit type check?
Best wishes,
Matthew
--
"Rogues are very keen in their profession, and know already much more
than we can teach them respecting their several kinds of roguery."
- A. C. Hobbs in _Locks and Safes_ (1853)
Matthew X. Economou wrote:
> In the case of classes and the slot-value accessor, how could one
> portably augment slot-value such that it would include strict type
> checks, or is one forced to create their own accessor function which
> would include an explicit type check?
Kenny won't like this, but you can use the CLOS MOP for this:
(defclass enforced-types-class (standard-class)
())
(defmethod validate-superclass
((class enforced-types-class)
(superclass standard-class))
t)
(defmethod (setf slot-value-using-class) :before
(new-value (class enforced-types-class) object slot)
(assert (typep new-value (slot-definition-type slot)))
[Untested.]
Your classes have to be instances of that metaclass:
(defclass foo (...)
(...)
(:metaclass enforced-types-class))
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
In article <·············@irtnog.org>,
"Matthew X. Economou" <···············@irtnog.org> wrote:
> Are type specifications in Common Lisp intended to enforce constraints
> on the type of a place's value (whether that place is a slot, a
> function's argument, a lexical or dynamic binding, etc.), or are type
> specs used only for optimization (if those declarations are used at
> all)? For example, if I define the following class in clisp, I can
> assign values to the slot that violate the type specification:
>
> [1]> (defclass test ()
> ((mode :type (member :one :two :three)
> :initform :one)))
> #<STANDARD-CLASS TEST>
> [2]> (setq test-instance (make-instance 'test))
> #<TEST #x10202FF5>
> [3]> (slot-value test-instance 'mode)
> :ONE
> [4]> (setf (slot-value test-instance 'mode) 1)
> 1
> [5]> (slot-value test-instance 'mode)
> 1
>
> (I experienced identical behavior in SBCL and CMUCL.) I would have
> expected that, at the default safety and optimization settings, an
> implementation would signal a type error when a value doesn't match a
> place's type specification.
>
> Could a implementation enforce type specifications and still be
> conforming? (From this behavior, I take it that portable code cannot
> rely on type specifications and must include explicit type checks as
> needed.)
>
OpenMCL checks.
joswig$ openmcl
Welcome to OpenMCL Version 1.1-pre-070214 (DarwinX8664)!
? (defclass test ()
((mode :type (member :one :two :three)
:initform :one)))
#<STANDARD-CLASS TEST>
? (setq test-instance (make-instance 'test))
#<TEST #x300040D995FD>
? (slot-value test-instance 'mode)
:ONE
? (setf (slot-value test-instance 'mode) 1)
> Error: The value 1 can not be used to set the value of the slot MODE in #<TEST #x300040D995FD>, because it is not of type (MEMBER :ONE :TWO :THREE).
> While executing: #<CCL::STANDARD-KERNEL-METHOD (SETF SLOT-VALUE-USING-CLASS) (T STANDARD-CLASS T STANDARD-EFFECTIVE-SLOT-DEFINITION)>, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 >
In general most of the time Lisp systems won't check this.
Some (SBCL, CMUCL) may statically check during compilation
and give warnings.
> In the case of classes and the slot-value accessor, how could one
> portably augment slot-value such that it would include strict type
> checks, or is one forced to create their own accessor function which
> would include an explicit type check?
>
> Best wishes,
> Matthew
"Matthew X. Economou" <···············@irtnog.org> writes:
> Are type specifications in Common Lisp intended to enforce constraints
> on the type of a place's value (whether that place is a slot, a
> function's argument, a lexical or dynamic binding, etc.), or are type
> specs used only for optimization (if those declarations are used at
> all)? For example, if I define the following class in clisp, I can
> assign values to the slot that violate the type specification:
>
> [1]> (defclass test ()
> ((mode :type (member :one :two :three)
> :initform :one)))
> #<STANDARD-CLASS TEST>
> [2]> (setq test-instance (make-instance 'test))
> #<TEST #x10202FF5>
> [3]> (slot-value test-instance 'mode)
> :ONE
> [4]> (setf (slot-value test-instance 'mode) 1)
> 1
> [5]> (slot-value test-instance 'mode)
> 1
>
> (I experienced identical behavior in SBCL and CMUCL.) I would have
> expected that, at the default safety and optimization settings, an
> implementation would signal a type error when a value doesn't match a
> place's type specification.
>
> [...]
>
> Best wishes,
> Matthew
Hi,
for SBCLhttp://www.sbcl.org/manual/Declarations-as-Assertions.html#Declarations-as-Assertions
says the following:
"Full Type Checks
All declarations are considered assertions to be checked at runtime,
and all type checks are precise.
Used when (>= safety (max speed space compilation-speed).
The default compilation policy provides full type checks."
This seems to be the default policy.
Your example gives me (using SBCL 1.0):
CL-USER> (setf (slot-value *inst* 'mode) :four)
The value :FOUR is not of type (MEMBER :THREE :TWO :ONE).
[Condition of type TYPE-ERROR]
Christian
From: Matthew X. Economou
Subject: Re: Enforcing type specifications
Date:
Message-ID: <uzm74q0ll.fsf@irtnog.org>
>>>>> "Christian" == Christian von Essen <·········@mvonessen.de> writes:
Christian> SBCL says the following:
Christian> "Full Type Checks All declarations are considered
Christian> assertions to be checked at runtime, and all type
Christian> checks are precise.
Christian> Your example gives me (using SBCL 1.0):
CL-USER> (setf (slot-value *inst* 'mode) :four)
Christian> The value :FOUR is not of type (MEMBER :THREE :TWO
Christian> :ONE). [Condition of type TYPE-ERROR]
I tried my example program on SBCL under FreeBSD when I posted, but I
didn't receive that error. Thanks for following up with a pointer to
the documentation.
Best wishes,
Matthew
--
"Rogues are very keen in their profession, and know already much more
than we can teach them respecting their several kinds of roguery."
- A. C. Hobbs in _Locks and Safes_ (1853)