Kaz said:
["Followup-To:" header set to comp.lang.lisp.]
Pillsy wrote:
I might, but if I wanted it to inherit from Number, I could certainly
choose to have it inherit from Number. I'm just not sure that's the
way to go from a design standpoint, though admittedly I haven't
thought about the question a whole lot..
Taking it as a given that Complex should be a subtype of Number, how
else would you go about doing it?
Are you asking about implementation strategies about how to add
this ANSI CL feature to Seamus MacRae Imaginary Lisp.
No; there's no such thing as SMIL anyway.
Obviously, there is. It may not be implemented, or fully specified,
but it's whatever Lisp language you are talking about in this thread.
Being a competent engineer and all, you wouldn't be caught dead spewing
nonsense about a language you know nothing about, such as Common Lisp,
right?
I was asking Pillsy to clarify
something that he wrote, and how he would do something. And since you're
not Pillsy, it is very odd for you to jump in at this point.
How do you know I am not Pillsy? Guessing again?
Yes really.
In Lisp? Surely you jest. At base, it has no static types and precious
few dynamic ones (integer, maybe a few other numerics, cons cell,
There is no static type, only type. Static type is simply the situation when a
type is being analyzed or otherwise manipulated prior to run time.
When we use a constant like 42, we don't call that ``static valuing'',
implying that it's a different kind of value from the situation
when some variable x holds 42.
I don't understand ``precious few''. If a language has a precious few types,
but all values have a type, then everything has type, right?
How many types must a language have before it's typed?
My statement ``Originally, everything had type'' was meant in contrast to the
current Common Lisp situation, in which everything has /both/ a type and class.
This is very language specific. An OO language designed from scratch today
might have only a single concept: just class.
string, symbol, nil, and little else).
Disclaimer: I'm writing strictly about Common Lisp (and in this case its
predecessors), not Seamus MacRae Lisp, which I know next to nothing about.
This seems to be checking some programmed-in notion of types, not
compile-time types of any kind.
Why have you chosen to contrast ``programmed-in notion'' against
``compile-time''?
In Common Lisp, the above is an expression, a call to subtypep. The subtypep
function takes two arguments which are types. Types are represented by symbols
(among other things). The symbol number represents the number type, and the
symbol complex represents the complex type.
If this expression is being compiled, then in fact we do have a situation in
which types are known at compile time: they are named right there! This is
actually a constant expression which can be compiled down to the constant T; the
compiler can know that subtypep is a standard CL function, and that it returns
T when applied to these particular arguments.
Anyway, the point was that Lisp has these types in that subtype relationship.
You could program this behavior in any language.
Terrific. An example (e.g. Java) would go a long way here.
Maybe a bit. At the cost of lots of debugging later on, in big enough
systems.
You have asked for evidence when people claim that this isn't a big
problem. Where is your evidence that it is?
In computer programming, a lot of aspects of the behavior of a program
are susceptible to compile-time staging, not only type.
What is your rational justification for being obsessed with doing this with
type?
Type is the simplest, most trivial aspect of a computer program.
Errors in type are among the easiest to debug.
The burden of proof rests on those who claim that any property X of a computer
program should be simplified and staged to compile time.
I have stated it repeatedly. You keep ignoring it.
Pardon me. Would you mind citing a Message-ID of the article containing
this evidence? I can't find it.
Well, there we are. I guess we are now in agreement.
So why am I still apparently only 1/3 of the way through your
interminably long post?
I assure you that the post does terminate. In terms of raw volume, I think you
are winning. I have not posted here nearly as much as you. You're
single-handedly taking on what seems to be at least half a dozen people.
Easy: what would have been caught in seconds at compile time, or even
instantly in the IDE when editing (red squiggly underlines: another
feature untranslatable to a box of pure ASCII), instead isn't caught
until run-time and possibly far from the true location of the error.
State-of-the art static typing systems also locate errors sometimes
far from the true location. You might want to Google for "Hindley-Milner"
to discover how typing is done in post-deluvial static languages.
Seconds of debugging becomes minutes at best, hours at worst.
Say the downside is 30 minutes.
Now note that type errors are an estimated 30% of bugs.
Aha, numbers. Where do these numbers come from? Can you cite your source?
What exactly is a type error? If, in a static language, two declarations do not
match, is this considered a type error, and is that counted toward the 30%
statistic?
Would we have that type error in a dynamic language?
A bit more up-front keyboard typing.
Do you think that every dynamic program can become a static one,
with only a ``bit'' of extra keyboarding?
How much is a bit? 10% more code?
Maybe more thought as to what
should be what and going where during design and coding, but that will
pay off as an investment down the line.
How about allowing the progrm to be easily changed with respect to
changing requirements? The world is a changing place.
There's a risk you won't be able to mischievously sneak a Float into a
group of Strings...
No, I am not. I am asserting that they balance out in favor of static
typing.
Based on what? Religious faith?
Then get some and post it.
You first.
This is the kind of worthless anecdotal "evidence" that all too many
people mistake for the real thing.
It's better claims from people who have no experience with dynamic typing, and
are purely guessing.
You'll also find that all of Java's "de facto macros" lack multiple use
of any argument, and so don't run into the variable capture/global
variable/multiple evalaution trichotomy.'
Yes, well these de-facto macros have to take that into account in their code
generation. The Java compiler, when faced with synchronized (expr) ... has to
generate code which evaluates expr to an object reference, and then store that
reference in some hidden variable. Then places in the expanded code which
require the value of the expression refer to the hidden variable; they do not
re-evaluate the original expr.
In macro systems, this is addressed in two ways. In the Scheme language,
which is a Lisp dialect, there are hygienic macros in which these issues are
taken care of automatically. Hygienic macros are cool, but some non-hygienic
things are awkward to do in them. In Common Lisp macros, hygiene is implemented
by the macro writer, in various ways.
A common strategy is to generate some unique symbols which are used to
name hidden variables.
Suppose we have a three-function API for locks:
(monitor-enter m) ;; enter monitor m
(monitor-leave m) ;; leave monitor m
(ensure-monitor o) ;; ensure object o has a monitor and return it
In Lisp we have the unwind-protect construct for running cleanup statements
no matter how an expression terminates; we will use this in the expansion.
Given the expression
(synchronized obj s1 s2 s3)
We want to generate code along these lines:
(let* ((hidden-obj obj)
(hidden-mon (ensure-monitor hidden-obj)))
(unwind-protect
(progn (monitor-enter hidden-mon)
s1 s2 s3)
(monitor-leave hidden-mon)))
Of course we won't call the hidden variables by these names; we will let the
compiler name them by calling the gensym function at macro-expansion time.
(defmacro synchronized (obj &body statements)
(let ((obj-var (gensym))
(mon-var (gensym)))
`(let* ((,obj-var ,obj)
(,mon-var (ensure-monitor ,obj-var)))
(unwind-protect
(progn (monitor-enter ,mon-var))
,@statements)
(monitor-leave ,mon-var))))
Expansion test:
[1]> (macroexpand '(synchronized a b c d))
(LET* ((#:G3131 A)
(#:G3132 (ENSURE-MONITOR #:G3131)))
(UNWIND-PROTECT (PROGN (MONITOR-ENTER #:G3132)) B C D)
(MONITOR-LEAVE #:G3132))
Looks good. So you will find that properly written Lisp macros share
this property of the properly written Java compiler features: no
unexpected capture, or multiple evaluation.
Oh, and by the way, there is one more piece to the hygiene puzzle. Note how
our macro expands to a body of code that uses some functions and operators.
There could be a problem if a function like ensure-monitor is locally
redefined. Typically this is dealt with using packages. It would really be,
say, (thread::ensure-monitor ...). Only you would probably not have to write
the explicit thread:: qualification because your defmacro would be in a file
where the thread package is in effect. Further, Conforming Lisp programs are
not allowed to redefine standard functions and operators like unwind-protect
and progn.
What's the difference, in this context? Can your CPU run assembly?
I can feed either assembly or C to a compiler front end driver and get an
object file.
You're jumping to unwarranted conclusions about me.
Is that so? I haven't ever had version control problems with yacc or bison files.
So the problem must be on your end. Somewhere between the keyboard and chair.
I don't have serious
problems with Bison and version control.
I don't have problems with Bison and version control, period.
I do anticipate there could be
serious problems with Lisp code rewriting the (foo foo) bits of itself
and version control.
Maybe in Seamus MacRae Lisp, if you don't design it properly.
If that is supposed to be a statement about Common Lisp, then it's a very
poor, inaccurate guess.
The intermediate results of macroexpansion are not written to a file.
There isn't any more of a version control problem with (foo foo) rewriting
itself than there is a problem in Java with synchronized (foo) { bar; }
rewriting itself.
I was shown a screenshot and told by a known hostile entity and probable
liar that it was emacs, and the screenshot showed something that
resembled emacs the way the Eiffel Tower resembles a tea saucer.
Funny, I looked at the PNG and saw only Emacs.
I didn't know Slime could do embedded graphics. I.e. evaluate a Lisp
expression, and the resulting value is a graphic. Cool.
I'm not an Emacs user, but I believe the PNG.
I find that particularly unlikely to be true. I'm adding you to my list
of "probable liars" in this thread.
What is a probable liar? Someone who offends you with facts that
don't agree with your pre-conceived notions?
Wouldn't it be easier to maintain a list of non-liars?
If you want to list probable liars one by one, you will eventually
need a few gigabytes of space to represent most of the entire world.
Just assume everyone is a liar. And, whatever you do, do not Google
up for a single fact to confirm or refute anything. The results of
search engines are all lies also.
I'm sorry, but I don't know of any "Seamus MacRae Lisp".
Right; I will substitute the proper name as soon as you share it with us.