From: Nathan T. <nb...@nb...> - 2013-10-18 22:53:24
|
Paul Khuong <pv...@pv...> writes: > In article <87o...@nb...>, > Nathan Trapuzzano <nb...@nb...> wrote: >> And since function type declarations also declare return >> types, I figured it made more sense to keep the FTYPE declarations and >> remove the TYPE declarations from the DEFUNs. > > There is a difference: FTYPE declarations describe how the function is > called. In theory, this can make it difficult to specialise a function > with FTYPEd information. SBCL and CMUCL are slightly more aggressive > than strictly allowed by the standard and do propagate that information. > So, in practice, for SBCL, the difference is tiny. I'm new to Lisp. What do you mean by "specialise a function"? Are you able to show me in the standard where such propagation is prohibited? >> However, when I ran some tests after removing the declarations, I >> noticed that performance had taken a huge hit. Certain procedures took >> almost twice as long as they had taken before I had removed the type >> declarations. (The optimize setting being (optimize (debug 0) (safety >> 0) speed).) Can anyone here explain why this might be? > > One common issue is with assignment to formal parameters (and with > default values for optional/keyword arguments sometimes). FTYPE > declarations only describe calls to the function. Thus, even with SBCL's > aggressive interpretation of function type declarations, > > (declaim (ftype (function ((mod 1024)) (values t &optional)) foo)) > (defun foo (x) > ... > (setf x (bar)) > ...) > > does not guarantee that X is of type (mod 1024) after SETF. Of course, > something else might be happening, and it may even be an issue the > compiler; it's hard to be more specific without concrete examples. > > If portability is not too much of a concern, > (setf sb-ext:*derive-function-types* t) > will record inferred function types in the global environment. This must > sometimes be combined with the unportable VALUES declaration to describe > return types. In the definitions I have in mind, there are no assignments, so that can't be it. I'm a little confused by your answer. You say above that SBCL and CMUCL do propagate information, but here you say (I think) that that only happens if you set that variable to T. Have I misunderstood you? Also, what do you mean by "unportable VALUES declarations"? >> On a related note, if I declare a function's return type in an FTYPE >> declaration and bind a variable using the function, as in: >> >> (declaim (ftype (function (&rest) <type>)) foo) >> >> (let ((var (foo a b c))) >> ...) >> >> will the compiler infer that VAR has type <type>, or should I declare >> that at the top of the LET's body (assuming I want maximal performance)? > > Yes. Something like (function (&rest t) (values <type> &optional)) is > even better: it specifies that a single value is returned. Good to know, thanks. However, I'm still not really sure what I should do. Should I add those TYPE declarations back in despite the fact that they're already there in the FTYPE declarations? Why else would removing the TYPE declarations cause a performance hit? |