ccl
ccl copied to clipboard
declaim inside a defmethod does nothing
1: Go to a repl 2: enter (defstruct foo ()) 3: enter (defmethod bar (a) (declaim (type foo a)) (print a)) 4: enter (bar 'a)
No conditions signaled. Okay, but step 3 should give me a warning that declaim is ignored.
Same thing for declare.
Fare to argue: http://www.lispworks.com/documentation/HyperSpec/Body/m_defmet.htm ... declaration---a declare expression; not evaluated. ...
But still, a warning or note would be nice...
- Why is the slot name in
DEFSTRUCT FOO
namedNIL
? - Why are you using
DECLAIM
in this position? Did you meanDECLARE
? - What do you mean by "declaim is ignored"?
- Doesn't matter, call it whatever you want.
- Still doesn't work.
- Nothing happens with the (bar 'a) call With declaration at least you'd expect a signal on incorrect type, or on compilation a warning of ignored type decleration/ declemation.
With declaration at least you'd expect a signal on incorrect type
Standard-wise, CLHS Declaration TYPE disagrees:
During the execution of any reference to the declared variable within the scope of the declaration, the consequences are undefined if the value of the declared variable is not of the declared type.
Therefore, specficiation-wise, CCL is allowed to do whatever when (bar 'a)
is called. More, the current behavior from CCL when evaluating (defstruct foo) (defun bar (a) (declare (type foo a)) (print a)) (bar :x)
is consistent with what ECL, Clasp, ABCL, CLISP, ACL, and LW do, which is to print :X
without any warning. Only SBCL signals a warning, and that is because of its "treat declarations as assertions" approach to compilation code that is unique across the contemporary Lisp world.
on compilation a warning of ignored type decleration/declemation
I don't understand that part - why would a warning be signaled if a known non-erroneous declaration is ignored by the compiler? Also, what do you mean by "ignored" in this context?
In addition, declaim
in a non-toplevel position is equivalent to putting a defun
inside a function body - it will not have the same effect as declare
does.
style-warning or note, to be nice to the user.
SBCL will tell you you don't want a declaim, and deleration will give a type check.
Yes, you could ask a style-warning from the implementation, but note that a conforming implementation may ignore any or all declarations but the SPECIAL declaration. What does the ccl documentation say, and is this in discrepancy with the observed behavior?
Otherwise, declaim has compilation-time effect only when it's toplevel. Otherwise, your declaim was equivalent to a
(proclaim '(type foo a))
which has only run-time effect. What effect could a type declaration of a symbol have at run-time, when the code has already been compiled long time ago, in a galaxy far far away, and when the link between the symbol and the variable as long disappeared?
Slids, you must not confuse type declarations with type checking. For type checking, you should use check-type:
? (defstruct foo
nil) ; why not, it's allowed; you get (foo-nil (make-foo :nil 42))
FOO
? (defmethod bar (a)
(check-type a foo)
(print a))
#<STANDARD-METHOD BAR (T)>
? (bar 'a)
> Error: The value A is not of the expected type FOO.
> While executing: #<STANDARD-METHOD BAR (T)>, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
1 > :r
> Type (:C <n>) to invoke one of the following restarts:
0. Return to break level 1.
1. #<RESTART ABORT-BREAK #x158909D>
2. Assign a new value of type FOO to A
3. Return to toplevel.
4. #<RESTART ABORT-BREAK #x158967D>
5. Reset this thread
6. Kill this thread
1 > (:c 2)
Invoking restart: Assign a new value of type FOO to A
New value for A :(make-foo :nil 33)
#S(FOO :NIL 33)
#S(FOO :NIL 33)
?
Using a declaration, it's you telling the compiler that you will never call bar with an object that is not of type foo. Therefore the compiler can assume that A is bound to a FOO. If then you lie to it, calling (bar 'a), then: 1- your call to bar is not conforming. 2- ccl is allowed to do whatever it wants, including locating your house and sending a nuclear missile on it, therefore 3- be happy it just does what you told it to do, ie to print the object bound to the parameter A.
Again, note that with:
(defmethod bar (a) (declare (type foo a)) (print a))
the problem is not in defmethod, but in the fact that you writing (bar 'a)
is not conforming. So at most you could complain that the tools you have don't do anything about this 4th step. Should the tool that would detect non-conformity to be ccl? or should we allow implementation to have some behavior in presence of non-conforming code? I guess this question is the justification of sbcl behavior. But this is not necessarily a good thing. With code such as:
(let ((v 'a))
(check-type v foo)
(assert (typep v 'foo))
(bar v))
the declaration of the type foo for the parameter of the method bar is perfectly justified, since the programmer ensures that only values of type foo will be passed to bar. If some tests were implemented by ccl in the method with the declaration like sbcl does, or in the call site (bar v), then those tests would be redundant with the check-type you should have written above (bar v). So why should the compiler generate those redundant tests?