Anton Ertl wrote:
>>No, the thing does not cause any problems at all.
>
> Yet.
>
>> It shows that the
>>equivalence for all practical purposes is correct, and your concern is
>>academical.
>
> Well, then why do you want to break that equivalence?
Because it was an unintended consequence of a misformulation of what
COMPILE, is supposed to do. It should *compile* something. It should not
add interpretation semantics.
I think our main difference is that I consider the current COMPILE, as
broken and misspecified, and you think it's god-given. It's not. It's
Mitch-Bradley-given, and Mitch Bradley had explained what he wanted it to
do. And following that explanation, the spec of COMPILE, in ANS Forth is
simply wrong.
>>You wouldn't assign a word with special compilation semantics
>>to a deferred word, because it already would be broken that way.
>
> Depends on what you expect. I guess you are thinking of a changeable
> SYNONYM. I would hav thought that your universal xt and broken
> "COMPILE," are intended to achieve that with an unchanged DEFER (just
> like for the interpreter loop). If it does not achieve that, maybe
> your concepts are not as good as you think.
How would that be possible? The unchanged DEFER uses EXECUTE on the token,
never COMPILE,. So how would that work without other changes? The token
knows how to compile, but the unchanged DEFER can't access this.
> OTOH, I don't expect DEFER to be a changeable SYNONYM, just like I
> don't expect ALIAS to be a SYNONYM. I would just define a new word
> for changeable synonyms, and that may or may not be tied to your ideas
> about xts (preferably it would not depend on them).
You probably would use your nt for that. This is something I absolutely
hate about typical Java code: Tons of types which are slightly different,
and do almost the same, but are incompatible, you often can only do forward
conversions (but not backward to where this thing came from), and it all
wraps onion layers around the real thing. Don't add things like this to a
language. Try to reduce the number of types to what you actually need.
> Here you suggest a version that depends on them:
>
>>: [defer] ( "name" -- )
>> defer [: >body @ compile, ;] set-compiler ;
>
> But it would be just as possible to write a [defer] without breaking
> "COMPILE,", or (with a different interface) to write it in Gforth
> 0.7.0 (you would either pass the name, the nt or the xt and ct to the
> IS replacement).
You see your inflation of types, which do almost, but certainly not exactly
the same thing, which lead to confusion and again subtle bugs.
> However, looking at the example again, I expect a deferred word to
> bind at run-time, not at deferred-word compilation like your [DEFER]
> does. I have not seen an example where such a changeable synonym that
> binds at compile time when it is compiled, and at run-time when it is
> interpreted, is useful.
That's probably why we don't have such a thing. BTW: The special-
compilation semantics OOP methods in BerndOOF are also all early bound, so
they actually don't go through a method table. But that might change if we
think of them as part of a Meta-OOP package, where different OOP systems
might want to implement them slightly differently.
> The " example is not convincing, because you cannot use S" and C"
> interchangeably (different stack effects), so switching them around
> dynamically makes no sense. What you try to achieve with that can be
> achieved already with SYNONYM and search order.
Maybe. The " example would be introduced as harness code for code that uses
" instead of C" or S".
> [...]
>>Only if they had, it would be a potential problem. You might
>>want something like [method] to create such a selector, which then would
>>allow you to define compiler macro methods (there's a place for them,
>>BerndOOF has several).
>
> So you can think of potential problems. If combined words are used
> more commonly than now (and I guess you would be among the frequent
> users), the problems will eventually show up in reality.
Which means go forward, and implement BerndOOF using monotokens, and see
when it starts to cause problems.
>>Yes. But on the other hand, IMHO this equivalence is an artificial one
>
> Why do you think so?
>
> Looking at the DEFERS and [BIND]/SUPER/:: examples, it seems pretty
> natural; did you even consider for one second that you should write
> "POSTPONE literal POSTPONE execute" instead of "COMPILE," when you
> originally wrote that code?
Let's go back again, and let's assume we have a POSTPONE method (there is),
which we want to override (which we can't ATM), say for debugging purposes.
So we do
: postpone ( "name" -- ) compile-only-error ;
comp: ( xt -- ) drop ." Print some debugging stuff" super postpone postpone
;
super as literal+execute would be clearly wrong here. Note that we need
this double "postpone", because the super postpone just performs the
compilation semantics in the super context, and there, it just postpones the
next word. Which is postpone in the super context - that's what we want.
BTW: Most of those state-smart words in BerndOOF are state-smart for
optimization, not as compilation macros. We want use COMPILE, on them,
definitely, because we want to optimize the code.
>> and
>>comes out of a mis-specification of compile,, as you actually don't have
>>access to the compilation semantics of an xt in ANS Forth.
>
> In ANS Forth compilation semantics is bound to named words, not xts.
Yes, this comes from the immediate flag, which is a header flag, and not
available through the xt.
> There are two places where it occurs: When the text interpreter
> processes a (named) word in compilation state, and in POSTPONE (which
> also takes a name).
Yes, but if you think the concept further, and we do that, we need
compilation semantics on tokens that are detached from their names, and that
detaching happens before we know if we want to compile them or just
interpret them.
> I think that COMPILE, is well specified. Why do you think it is
> mis-specified?
You still don't want to accept the rationale Mitch Bradley has given for
COMPILE,, and the fact that COMPILE, was added late in the process and
didn't get much review.
> And please post your "improved" specification again.
COMPILE, performs the compilation semantics of non-immediate words. The
compilation semantics of immediate words is performed with EXECUTE.
immediate words are a legacy of the STATE-smart universe. We can't get rid
of them quickly, but we know we need something better.
>>The fix for that IMHO is to provide interp, for the purpose you want.
>>That word makes pretty clear that you append the interpretation/execution
>>semantics, and are not actually attempting to really compile the token.
>
> You mean that we should change "COMPILE," to do something different
> from what it does now, and introduce "INTERP," to do what "COMPILE,"
> does now? Memories of Forth-83 arise.
Well, VFX has already changed that 15 years ago. If there was a serious
problem with that approach, I would have found it. I found quite a number
of problems with VFX (for that kind of "guru code" I write). COMPILE,
wasn't one. And I do write my own interpreters which use COMPILE, a lot,
especially in BerndOOF.
Stephen Pelc accused me that my attitude of porting programs to other
systems (by improving their implementation quality rather than lowering my
expectations) would not make the next port easier, and he's right. It will
not make *my* next port easier, but it will make the next port of all others
easier, because the systems behave more alike.
> An alternative would be to just leave "COMPILE," as it is and
> introduce a new word (maybe "COMPSEM,", but you sure can come up with
> a better name) that does what you want. You would have to use
> "COMPSEM," in the interpreter loop, but the FIND would be cleaner.
IMHO we just can't have both Mitch's interpreter loop and what you want.
From my point of view, Mitch's interpreter loop is more important, because
this really does exist (e.g. in BerndOOF - if VFX's COMPILE, would do what
you want it to do, BerndOOF quite likely wouldn't work).
MPE introduced [INTERP] <name>, because they had two use cases for that,
both with names. Given that it just expands to ['] <name> EXECUTE, it's not
sure if that was actually necessary.
> Or, if you want to keep the Bradley interpreter loop unchanged,
> implement FIND to return different xts depending on STATE (like Gforth
> is doing now). You can still introduce "COMPSEM," if you want.
I can't let FIND return different xts for that, because an executable
"compilation token" always is a pair of xts (as in Gforth). This won't
work.
There's some place for a NAME>COMP EXECUTE replacement, which handles both
the immediate case and the separate compilation semantics case.
> Yes, except that what you call "run-time semantics" is called
> "execution semantics" in ANS Forth, and in ANS Forth the run-time
> semantics of some words is a helper for defining the compilation
> semantics of that word.
Nah. The execution semantics of an immediate word is its compilation
semantics, and then it can add some other run-time semantics.
>> Now, COMPILE, is specified to perform the
>>default, this is breaking the symmetry, and making things more
>>complicated.
>
> What symmetry?
As described in the ANS Forth standard, words have interpretation and
compilation semantics. ANS Forth's COMPILE, performs default compilation
semantics even on those words which don't have default compilation
semantics. This is a part of COMPILE,'s behavior, which should have better
not specified. And in fact, IMHO VFX shows that leaving that open is not a
problem at all - other parts of VFX were problems, and have been fixed
since, but the non-standard COMPILE, is not one.
> What makes things complicated is combined words.
No, what makes things complicated is this mess of immediate and state-smart
to make words have non-default compilation semantics, and to detach the
compilation semantics from the xt.
>>The reason is that at that time, non-default compilation semantics was
>>specified by IMMEDIATE, and the xt doesn't know if it's immediate or not.
>
> And? Why should it be necessary to know that?
Because if it doesn't know that, you have to either introduce a new type
(the nt), or you have to pass around strings and maybe even contexts
(vocabulary stacks)... and then you end up with the bag of problems you
have with MPE's source inliner. You don't want to have that, you want to
have tokens. And I don't want to have yet another token, which is not
directly executable, because that did cause significant problems in Gforth,
when I started with the recognizers.
>>Let's assume we do what you suggest: add another method to the vtable, and
>>add another word to do "the compiling", which would be something different
>>than compile,. Now, you might have set-compiler and set-compile, to set
>>them. How to choose which is the appropriate one? Most of the time, it
>>doesn't make a difference, so chances are high that people will not
>>understand why there are two, and treat them interchangeable. It will
>>sometimes result in non-optimal code (if the optimizing version ends up in
>>compiler, but should end up in compile,), sometimes in bugs like the
>>above, where you can't use COMPILE, to get at the interpretation
>>semantics.
>
> These are not bugs. These use COMPILE, as specified.
The spec is buggy. As I said, you can't have both: The spec for COMPILE,
and Mitch's interpreter. Mitch's interpreter is the reason to specify
COMPILE,, and it went wrong. Spec bugs are the worst kinds, because some
people, like you, think the spec is always right. In this case, it is just
wrong, and we need to fix it.
> OTOH, if you are right, you should be able to point to lots of uses of
> COMPILE, where the current usage of COMPILE, is wrong, because the
> programmer actually intended to perform the compilation semantics
> instead of appending the intepretation/execution semantics.
Look at BerndOOF, it does that. It uses COMPILE, on all non-immediate
words, and wants compilation semantics. If you replace the immediate words
with special-compilation semantics words, this part of BerndOOF will still
work as it should. If you change the semantics of COMPILE, to what you
want, you have to keep the state-smart implementation.
Do you now tell me that state-smart is actually *not* evil, because it
harmonizes perfectly with your understanding of what COMPILE, should do?
> Until now
> we only know several cases that would be broken by the change you
> suggest for "COMPILE,". How many cases do you have that would be
> fixed by that change?
All the cases of Mitch's interpreter. As long as you stay with a immediate-
flag implementation, and have no special compile, words, you won't see the
difference.
>>If you have two things that do almost the same, but differ in sublte
>>things that happen only once in a blue moon, you better do just one of
>>them.
>
> Sounds like an argument against your "INTERP," (as well as against
> "COMPSEM,").
Yes, use ['] foo exeucte instead, don't give it a name. It's likely below
threshold of introducing a new name for it. If you deliberately want
interpretation semantics, this is how you get it. This is *not* the usual
case. Usually, when you want deliberate interpretation semantics, it's
because you reuse some word for defining a combined word. Then, you know
what you are doing.
> You can also look at how many uses of POSTPONE, are wrong.
You think POSTPONE where you really want [INTERP]? Works only in state-
smart systems. Yes, by removing state-smartness, you do break some
programs. You fix way more than you break, which is why this change is
accepted.
> Of course
> POSTPONE, is sufficiently different (different stack effect) that it's
> not easy to use it instead of COMPILE,. If so, and you are right
> about confusing "COMPILE," with the other words, that's an argument
> against going for a universal xt.
You can only reduce confusion about things like this if you *reduce* the
number of terms, states, and concepts. Not by increasing them, as you do.
The Forth approach at things is not through increasing complexity. It is
often by using ad-hoc approaches, which is why we have immediate and state.
But if we get at the limits, the Forth approach is to rethink, comprehend
the problem in total, and then remove the unnecessary cruft.