Question about Tachyon
David Betz
Posts: 14,516
I've been playing with Tachyon and its interactive capabilities a little lately and was surprised about some behavior I saw. In particular, I defined a word, used it in a second word, and then redefined the first word. I thought that the second definition would pick up the new definition of the first word but that doesn't seem to be true. I know it is normal for previous code to continue to use the old definitions in traditional Forth but I thought I remembered Tachyon handling this differently. Am I mistaken?
Here is a simple example. The word "bar" makes use of the word "foo". The first example works the way I expect but when I redefine "foo", "bar" still refers to the old definition.
Is this expected behavior.
Here is a simple example. The word "bar" makes use of the word "foo". The first example works the way I expect but when I redefine "foo", "bar" still refers to the old definition.
: foo 3 * ; ok : bar 100 foo ; ok bar . 300 ok : foo 4 * ; ok bar . 300 ok
Is this expected behavior.
Comments
With Peter's goading I was having another play with gforth today. Now you tell me one of my fundamental assumptions was wrong:
Call me stupid for thinking that "redefined" meant, well redefined !!
How is one supposed to cause the definitions in use by other words to be updated, I guess there is a way ?
It is possible in some Forths to redefine the code that a Word points to using the IS word. Words that allow redefinition using IS must be defined with the DEFER word. The DEFER word is used to create something similar to a function pointer.
Absolutely as bar compiled to point to foo via the vector table. When you create a new definition with the same name it doesn't try to do anything fancy, just simply do, rather than guess. Now if you perhaps named the new word foo2 so that you could still reference the old word too then you could get bar to actually execute foo2 instead of foo with:
REVECTOR foo foo2
So the vector for foo will now point to foo2 so that the code for old foo is now orphaned (no vector points to it) and instead points to the code for foo2.
The simplified bytecode for these definitions helps to understand this, here each line except the labels is one byte.
foo: <----(CALL VECTOR 240)
3
*
EXIT
bar: <----(CALL VECTOR 241)
BYTE
100
XCALL
240 (foo vector index) ---> (16-bit pointer to foo)
EXIT
foo2: <----(CALL VECTOR 242)
4
*
EXIT
So if you change vector 240 to point to foo2 then bar will call foo2 via vector 240.
The XCALL can be one of 4 general CALL opcodes (XCALL,YCALL,ZCALL,VCALL) which each lookup one of 256 vectors using the next bytecode as an index into the vector table. This scheme makes it a lot easier to write the initial kernel using the "Spin" compiler although it's not Spin but PASM or byte structures. Unlike conventional Forths which "interpret" 16-bit addresses which point to the code field, Tachyon is more like a regular CPU which reads opcodes, so that four CALL opcodes really have 2-bits of the vector address and the following byte has the other 8-bits. So there are no "code fields" as such, it's all bytecode composed of opcodes and operands.
Automagically changing things is not something I just want to happen and normally there is no need for it expect perhaps when things are being tweaked, so it's no problem to specially revector something in that regard. Yes, approaches are different because Tachyon has never been about academic exercises in languages, it's always been about how to get the most out of the Prop and to do it interactively too.
A lot of these features I don't find practical either because we only have 32K memory effectively and if it's all taken up just supporting fancy features that look good in demos then what can you really use it for when there's no memory left? For instance, when we create foo again we now also have to search the dictionary for older references. Then is this the only older reference, are there more? What do we do? Fine, there might only be a few steps and some decisions but there are a lot of things the final app will have to do and compile-time magic looks good but does the system need it and can it afford it?
I can feel my brain melting again.
I'm told that Forth has this dictionary full of words. Words are either predefined in the system, like "+", "-" etc, or user defined with the ": doSometing 10 . ;" syntax.
Then I'm told that words can easily redefined over the command line interface (REPL) for quick interactive development.
Now I find that words hang on to the guts of the sub words they use when those sub words are redefined with new guts.
Please someone tell me what is going on here?
Even in good old BASIC I can enter a new definition of line 100, for example, and my program changes exactly as I expect.
IF youse redefine a word, the definition is the only one found from that point onward. BUT stuff that is poijnting to the previous definition is still pointing to the previous definiton. I think they call it "operator overloading" in some languages.
But really, if you want to a functtion PRINTA that prints capitol "A" and a funtion PRINTA that prints a lower case "a": either make up your darn mind or call one PRINTa.
If you want ot go back to the definition that already in the dictionary and edit that, don't. That's an advanced thing that you will confuse you, as you have observed. Don't eat the elephant in one byte.
It's a matter of what one wants/expects/needs the compiler to do. I thought about this when I first wrote Tachyon and after running through different scenarios I decided not to do anything like that, just keep it simple. Since Tachyon uses vectors I wrote the REVECTOR word to allow me to patch and test, but it is used extremely rarely. So having a feature to foo foo sounds nice but do I need it?
There are so many ways of doing these things but the other thing to remember is there are Forths and there are Forths, some are designed for PC environments with large resources, others are designed to run on very small embedded processors with very limited resources (in today's terms) such as the Prop. Do we want the Prop as a mere "prop" to show off a language and clever little ways of doing things but incapable of doing much more because of a lack of resources? Yeah sure, just add this RPi or maybe this memory expansion card, use up all the I/O for it, and you can emulate an address/data bus and increase code size by 16 fold, just a bit slower, but is it practical? For one off it's fun, but I'm into building product so I keep it realistic and practical, and the big thing is, it has to work and it has to perform. Isn't that the whole reason for computer languages and programming in the first place? Not just to have books published and keep university departments and courses filled.
How does a 32K Prop compare to a 64-bit WinTel machine with gigabytes of RAM ? Yes, the Prop is minimalistic compared to the PC but we leave the PC on the desktop and run the Prop where the PC wouldn't have a chance. We are talking about an O/S + language + development utilities + application ON a 32K microcontroller. That should be really really good news and I am always dumbfounded when I hear comments about comparing everything under the guise of "language" to what is essentially the desktop PC + O/S????? That just never makes any sense in the real world. How can you have a PC style O/S language running on a 32K micro? Upgrade it until it is no longer a 32K micro? Apples and oranges, not the same.
Come on, a lot of people are still having trouble blinking LEDs on the Prop with their most excellent PC development systems yet you yourself know the state of the Tachyon O/S and how much functionality it packs in the Prop itself. You would think that this would be a big boast for Parallax that P1 can do all this? Still, they are busy pushing "learning" tools. What happens when they get beyond learning and demos and need to do some real stuff and then I wonder why would they do it with the Prop when a 50cent PIC will blink a LED just fine too? (except that they have a nice development environment on their PC).
I have only ever seen operator overloading in languages that have an idea about types.
For example in C++ you may define a type (class) of "Apple" and then define the "+" operator for apples to do whatever you like. Then when you write "+" in your code the actual version of plus that is used is decided by the types of the operands.
In a similar way we have polymorphism whereby there may be many functions or methods with the same name but they each take different numbers and types of parameters. The actual version of the function that is called is again decided by the types of the parameters in the particular call. But really, I have been hearing for ages that a major strength of Forth is it's interactive nature and how malleable it is from it's REPL. How easy it is to redefine things from the console. Which is quite true.
Now I find that malleability is not quite so straight forward. If not impossible.
The question is not about printing an "A" or an "a". What if my program works fine and now I want to change PRINT so that the output goes to a different device? No can do. Or at least not as easily as I was led to believe.
Now, I don't much care if I can do such redefinitions on the fly or not. It's not something I'm expecting to want to do a lot. But this feature did come as a surprise to me. It is not expected behaviour if you come from BASIC or JavaScript and so on. As long as I know we are good to go. Hmmm...seems I keep choking on the mouse every time I try to get it down
Once again, apples and oranges. Besides if you could do the job nicely in Basic then maybe you don't even need the Propeller chip. Since I design for production this is the design choice I would make early in the piece and if it's volume then the 50 cent PIC is designed in even if it's a gruelling task to code it all in assembler. However since when has there been this expectation that everyone should drop Spin or C or C++ or PASM or Basic and jump on the Tachyon bandwagon? I can't see it happening at all and one of the main reasons is simply to do with mindsets, but if you wanted to get the most out of the Prop then I would encourage those ones to not limit their mindset, to stop comparing apples and oranges, and consider Tachyon. As they say, the proof of the pudding is in the eating.
"Someone" mentioned malleability as if that were the standard that Forth or perhaps Tachyon should be judged by? Well once again it's how I want it to be which is what malleability is, to be able to shape it to one's needs, which I can. Someone else can go and shape it another way if they want and foo foo all they want.
Because I never touted redefinition as any kind of desirable feature that I need anyway but while the focus is on what Tachyon is not, it then ignores what it is, which is probably a whole lot more then we have time to talk about. If foo foo style redefinition was actually important beyond looking good I would implement it and as you know that would take me less than the time it takes to respond to this thread. Also if anyone needed to cram more into the Prop then they normally could, then yes, use Tachyon.
My compiler writing skills only extend as far as generating very suboptimal code from a simple minded, block structured, language in the style of C/Pascal so my hat is off to you and anyone else who can define their own language and make it work.
P.S. I do agree that such on the fly redefinition is not a lot of use. Certainly not a "must have" feature. I was just surprised that it gforth, and others it seems, did not work that way.
C'mon, you know that is not so. Remember, this is NOT an OS running on a workstation. Each command is a few lines of code that do exactly one thing for you, which might look like something an OS does, but its not is only that one thing and nothing more.
Each interface is hard codeed, that how far down into the hardware we are. We are not way up at an OS level.
Sal made standard interfaces in propforth, if you want to point to a different interface, you just plug it in and got. That is why propforth has a bit bigger memory foot print than tachyon, and runs bit slower. But that is NOT standard forth; standard forth is hardcodes the interface, since that is the hardware, and generally doesn't change. Sal designed for "plug in interfaces". Do you need fastest, or do you need plug in intterrfaces? You can ask for both, but something has to give.
We can do thing like change existing definintions so that previously defined function are affected. But its tricky, if you don't know what you are doing you will make an error. Just avoid the the tricky stuff, till you get used to not having a full OS.
I only time I use Tachyon is when I use the Propeller. That's a simple enough statement and quite correct. In some other buried post I even said that for me Forth works really well in a certain class of embedded controllers, not too small, not too big, and in fact hardly ever on a PC which is where most people are familiar with Forth and yet one I avoid because we have such glorious almost interactive IDEs in different language flavours, and in that environment I am really quite happy to program in something other than Forth. PC Forth on an old DOS machine kinda made sense, not any more.
I am definitely no elitist, more of a pragmatist, but I know I'm quite right in respect to the Prop because as I mentioned before about the proverbial pudding, I have seen the results to confirm my "hypothesis" if you like and it is no longer subject to hypothetical debate. It works, and it works very well.
Regarding David problem, Tachyon even more useless if I can't redefine word and use it immediately. Why Tachyon just simply no read word from vocabulary end execute them? Nonsence!
PS: Never advice me to use forth on propeller!
Please read the Forum Rules:
http://forums.parallax.com/showthread.php/134682-Forum-Guidelines
This thread opened with a simple question and we have the simple answer. And the reasoning behind it.
Tachyon may well not redefine words in the way we expect but it is designed that way and for good reason it seems. It turns out that other Forth like systems behave the same way, for example gforth. (I say "Forth like" because it seems they are all different, Forthers take pride in doing there own thing and I can't pin down the "Real Forth").
Certainly you can't redefine function and variable names at run time in most other languages at all. For example C, Pascal...
If you want weird try JavaScript. This code:
Prints out:
WTF you might think initially!