Special questions - burying in advance etc.
A Logo programming environment for Microsoft Windows
Brought to you by:
david_costanzo
While trying to find out how to improve our teaching, we wrote the following experimental program:
TO act
CLEARTEXT
BURYNAME [u]
SHOW BURIED
LOCAL [brand x y]
MAKE "brand [Will I be shared?]
MAKE "x 3 BURYNAME [x]
MAKE "y 7
MAKE "z 11
intermediate
MAKE "running? "TRUE
WHILE [:running?] [
MOUSEON [react_to_left_down MAKE "running? "FALSE] [][][][]
]
END
TO intermediate
LOCAL [pad] IFELSE NAME? "brand [MAKE "pad [are]] [MAKE "pad [are not]]
(PRINT [Local variables of act] :pad [shared with procedure intermediate])
LOCAL [u]
(PRINT [x y in intermediate yield] :x :y)
last_action
SHOW BURIED
(PRINT [u =] :u)
END
TO last_action
LOCAL [pad] IFELSE NAME? "brand [MAKE "pad [are]] [MAKE "pad [are not]]
(PRINT [Local variables of act] :pad [shared with procedure last_action])
(PRINT [product in last_action] PRODUCT :x :y)
MAKE "u 42
END
TO react_to_left_down
LOCAL [pad] IFELSE NAME? "brand [MAKE "pad [are]] [MAKE "pad [are not]]
(PRINT [Local variables of act] :pad [shared with procedure react_to_left_down])
(PRINT [left mousebutton pressed])
END
We wrute 'act' into the commandline and, after getting a result, pressed the left mouse button three times. The whole result in the consolewas the following:
[[buryname edall edallbtn namelist while] [] []]
Local variables of act are shared with procedure intermediate
x y in intermediate yield 3 7
Local variables of act are shared with procedure last_action
product in last_action 21
[[buryname edall edallbtn namelist while] [u x] []]
u = 42
Local variables of act are shared with procedure react_to_left_down
left mousebutton pressed
Local variables of act are not shared with procedure react_to_left_down
left mousebutton pressed
Local variables of act are not shared with procedure react_to_left_down
left mousebutton pressed
While the different results to mouseclicks (after u = 42) are understandable, some of the results above raise questions which I'd like to put now:
Sorry - my post is not yet complete. Some more questions are missing:
I think it'll be difficult to use BURY to get exactly what you want in this case. Unlike LOCAL, BURY won't automatically UNBURY when it goes out of scope, so the variable will remain buried. You could UNBURY it before a procedure exits, but that won't clean up if THROW/CATCH is used.
I think it'd be more robust to deal with whatever consequences there are of local variables being unburied. For most use cases, there's no consequence. I expect that your problem is that Little Helper randomly show the local variables in the editor depending on when a button is clicked. You might try to filter out the ones you know you want to hide.
Yes, but take in mind you've also buried
uas a global variable because it's never UNBURY'd.Yes. See the discussion in Support Request #29.
Yes.
Depending on timing that you can't control, event handlers may interrupt any procedure that's running and have access to all dynamically scoped variables of the procedure they interrupt. This might not have been intentional behavior, but it's the behavior inherited from MSWLogo.
Yes. You can shadow any variable (globally scoped or dynamically scoped) in the same way with dynamic scoping.
I think you're asking of you should use LOCAL or not because dynamic scoping is deeply rooted in LOGO and the only way to avoid it is to never use parameters. I personally always use LOCAL because I don't like to pollute the global namespace. I don't think there's an objective answer to your question, but perhaps LOCAL solves some problems you have but it's not a complete solution.
Related
Support Requests: #29
There are two issues at stake in these reflections, and I think we have now come a long way in understanding them. So let me briefly outline how we at pbreport think today.
Let me begin with dynamic scoping. We also prefer LOCAL definitions for all variables that are restricted to a special procedure. But we are not forced to pay attention to the effect of these definitions on called procedures - we can safely ignore their propagation via dynamic scoping.
When it comes to sharing content between caller and called procedures, we use parameters instead of dynamic scoping.
If we don't use dynamic scoping in the called procedures, there is no effect at all - and if we want to reuse the transferred names as new locals in called procedures, this is always possible because of shading. So we can behave as if dynamic scoping doesn't exist, and nevertheless we always avoid the pollution of the global workspace.
As for the event handlers, we always use global variables for them because they are the only ones that are always guaranteed to exist at the right moment. We can still keep order in the global area by making the reference to specific event handlers clear with special names.
In summary: We mostly pretend that dynamic scoping doesn't exist and that we only have the global scope as a common namespace.
We fear that a widespread use of dynamic scoping could be a source of many errors in programs with many procedures (as was the "go to" in ancient BASIC programs before structured programming was born.)
While avoiding dynamic scoping as well as polluting the workspace with too many global variables we expect that we can use FMSLogo even for big scaling and large programs.
For some use cases there are exceptions for experts. They can make use of dynamic scoping under the following conditions:
Practically this looks similar like in many lexical-scoping-applications of other languages, but regretably there are no closures possible.
The second issue is burying.
As we see it, burying allows to extend the language and its core of primitives by new commands and operators without showing their implementation to the user. It assists some kind of bootstrapping.
On the other hand, it should not be part of the application programming style.
While logolib allows to implement many language extensions without carrying a whole library with it, sometimes whole buried libraries could be loaded from the user.
All the buried subspace will not be stored together with the application program - it stores only the application program whereas single extensions in the logolib and libraries in the nearby storage will always be accessible in case of a new start of the application program.
This is the current state of our perspective.
If you have comments on it, I'd be glad to know them.
Since you asked for comments...
In case you missed a point I made earlier, parameters are dynamically scoped. The only way to avoid dynamic scoping is to avoid both parameters and LOCAL. To illustrate, consider procedures like this, where a variable name "variable" is a dynamically scoped parameter.
You can see that B can read and write to "variable" even though it's a parameter of the caller. After A exits, the variable goes out of scope and disappears, leaving nothing in the global namespace.
And you can see that the dynamically scoped parameter shadows a global variable and the dynamically scoped value is visible in B.
And another example that shows how the parameters in procedures with callbacks can introduce bugs if you're unlucky enough to use a variable that the procedure use:
To summarize, you can decide not to use LOCAL, but you can't practically avoid dynamic scoping. In my view, dynamically scoped variables do not create any additional pitfalls beyond those that exist for globally scoped variables and they can mitigate some of them.
Some additional comments:
1) I think you fully understand the purpose of BURY.
2) I agree that it's a good practice to access only parameters and LOCAL variables within a procedure.
3) Some of the games in the fmslogo-extras package safely access LOCAL variables in event handlers. The program structure guarantees that no callback can be called after the variables go out of scope. For the duration of the game, the variables are effectively global, but they disappear once the game is over. That said, it makes sense for Little Helper to rely on buried global variables.
4) I don't know how long is the longest program that can be written in FMSLogo. With a good structure and discipline, you should be able to write a program with 1 KLOC. I expect the largest program ever written is testharness.lgo, which I use to test FMSLogo.
5) Closures are nice, but they're hard for beginners to understand. As we discussed elsewhere, you can make your own closures in LOGO by putting the value of a variable into an instruction list that is later RUN. This is certainly an advanced technique.
Thank's a lot for your comments! But sorry, I guess I didn't express my thoughts very well .
I always thought that defining parameters is like defining local variables - and that as such they are also the top of dynamic scoping chains.
In our way of programming we do not hesitate to define most of our variables as LOCAL and to add more local variables by using parameters. More than that, we do not define global variables ouside of procedures, and we try to use them only if this is really necessary.
The only special thing is that we normally access available local variables and parameters only (!) in the procedure that defines them and not in the whole chain of called procedures which follows. Doing this has the same effect for us as if dynamic scoping wasn't there at all. We can even use the names in other local definitions, because they are shaded.
In other words - we often create a plethora of variables which are spread all over the procedure graph by dynamic scoping and which we could access. But we never access them outside their "own" procedure.
By the way - when I write
would it be okay to leave SENTENCE away and just write
?
Well - this is what I wanted to post first, while I'd like to discuss the other very interesting topics with my collegue tomorrow before referring to them.
After discussing the problem of closures in FMSLogo we went back to a HTML-JavaScript-CSS-course we gave a few years ago. For this course we did our own implementation of turtle graphics where "turtle" was an object class with all the known turtle-methods and two or three more.
By that time classes were new in JS. But during many years before JS hat prototypes and constructors and a well-known workaround based on closures which was called "function factory". Until now there are still many community members who say that closures with function factories are the best way of generalizing objects. A function factory is like an object class. It is the easiest and best understood way to deal with closures.
Please find attached a screenshot of three wheels which are softly rotating at different speeds and directions. We also attach the html-js-code of it. "playground.js" is our own implementation of turtle graphics, and the two p5-libraries stem from a very good and well known development by Lauren Lee McCarthy, who has now handed over the project to another Chinese artist.
We tried turtle graphics later in a Python-course. It was already available und also worked fine.
The reason why we finally switched to FMSLogo may not be evident at first sight, but there are at least three reasons which we'd like to explain later.
p5.js as well as Python are object-oriented.
p5 is a Browser-based extension of JS which is closely related to Processing and supported by the Processing Foundation. There is a very good book by Daniel Shiffman "The Nature of Code" which has a lot of examples from the natural sciences using object oriented models of things like particle systems, snowflakes, and of course L-systems.
Now we wonder whether we could work with object-classes in FMSLogo, too. We did some experiments and want to do more - but I'm convinced now, that object-classes can be used without any new development by using function factories and buried property lists, and by assigning classes to methods vice-versa than in other languages. Yes, it seems as if we can use FMSLogo as a language with object-classes generated by function factories. The most important feature is the assignment of a hidden state to each object which can't be accessed from outside.
FMSLogo seems to be a mighty list-oriented language which is far more than a toy for beginners.
Although we can achieve so much wíth FMSLogo as it is now, there are two topics which should have made some amendment in the future.
The first is animation. We learnt from p5.js that flickering can easily be avoided if you built a new image behind the scenes and switch it to the front screen every 1/60 second, which is done automatically without code from the user. It is done on the HTML-canvas. As I read in the documentation, FMSLogo can do something similar, but for me it's hard to understand and to perform. so - is there any easy way to achieve soft animation in FMSLogo?
The second may be less important, but has an impact on scalability. So I ask: Is it perhaps possible for FMSLogo in the future to allow not only local variables but also local procedures? There are workarounds even now, but it would be a great progress.
Sorry, I forgot to send the image. Here it is.
Manfred asks...
Yes, that's good, too. For this case, I wouldn't say one way is better than the other. I prefer not to use parentheses in examples.
Manfred asks...
You can use BITMAPTURTLE with a :rotatebitmap argument of "TRUE to get flicker-free animation. This uses a back buffer to compose the entire screen before blitting it. There is no other way to access FMSLogo's back buffer. There is no way to use turtle commands to draw on a back buffer and then flip it to the screen.
See this discussion for more details. The original post is lost, but the discussion remains.
Manfred asks...
At quick glance, I don't see why it's not possible, but I don't expect to work on that personally. If I had time for FMSLogo development, I'd be more interested in making it possible to assign a procedure to a variable. That said, the source code is licensed under the GPL, so anyone in the world is free to add whatever feature they like. You just need to convince one person.
In the meantime, you might be able to get close with COPYDEF and ERASE to replace a procedure's definition; BURY to hide the original; .DEFMARCO to execute in the caller's context; and CATCH to make sure you always restore the original when the caller goes out of scope.
Thank you for these comprehensive informations, especially those from 2018.
I'd like to show you how we implemented animated turtle graphics for courses in the html canvas in 2020 using p5.js, that means JavaScript for artists. So I attach included in a single zip-file
The animation is pretty simple to do, as soon as you have the turtle graphics. In an inner function there runs some kind of main loop which directs all actions to a hidden layer of the html-canvas and switches them to the screen as soon as they are ready (all 1/60 seconds, if possible). This method is used by artists in the Java-dialect Processing or in html with the help of JS and its library p5.js.
Many artists like p5.js and Processing, but for a general use there are shortcomings, especially the restriction to the frontend of the web and therefore no easy management of persistent data.
In your post of 2018 you used the word "sprite", which doesn't seem to appear in the FMSLogo documentation. My question is: Is there some kind of sprite-handling in FMSLogo, perhaps using rotating BITMAPTURTLEs? And can I reasonably install more of them? What happens, if they approach each other - is there any kind of overload or collision behaviour? Do they behaveas if they were in layers, and how are they ordered? How large can a rotating bitmap reasonable be before everything becomes too slow?
Well, we have some experience with our "copter" which seems like a small sprite - but what happens if there are more copters?
And is there any current or future way to do things like in our p5-exaples in FMSLogo, too?
We need to know the limits of FMSLogo well before we start our series of coursebooks which are tested in our current courses.
And as soon as possible we'll send you our final (and fully downward-compatible) amendment of FMSLogo as we use it for young people aged 14 or more.
Manfred Asks:
When I wrote "sprite" that in 2018, I meant
BITMAPTURTLEwith:rotatebitmapof TRUE. The source code refers to rotating bitmap turtles as sprites, but it's missing things that you would reasonably expect from a sprite. As a result, the term "sprite" was intentionally excluded from the documentation.Manfred asks:
There's no explicit limit on the number of bitmapped turtles. I'd expect that you could have a dozen turtle-sized bitmaps without a problem, but, as you add more bitmapped turtles or add large bitmapped turtles, it will eventually will become too slow.
Manfred asks:
BITMAPPED turtles pass through each other and get drawn on top of each other. There is no collision detection or sensing built into FMSLogo. A programmer would have to implement that themselves.
Manfred asks:
Yes, they're drawn in the bitmap order...turtle 1, then turtle 2, then turtle 3, etc.
Manfred asks:
It depends on your computer. With a HEADING that's a multiple of 90, the rendering should be fast. Otherwise, the rendering speed is proportional to the number of pixels in the bitmap. Most of the time is in anti-aliasing, so having lots of transparent (white) pixels next to each other helps.
Manfred asks:
I'd say that "small" is about the size of the original turtle or the spaceship in AsteriodMiner. I'd say the copter is medium-sized. I made bitmapped turtles as fast as I could, but maybe it's not fast enough for the way you want to use it.
If I were going to try that today, I'd first use BITBLIT to clear the picture, then redraw it. If that had too much flicker, I'd try rotating bitmapped turtles. I'd first draw each shape on a white background and BITCUT it into a bitmap. Then I'd map the three bitmaps to different turtles, set the background to blue, and have them rotate. Each turtle will be drawn as soon as it rotates, so the three won't spin synchronously. I have no idea if that's fast enough. Have you tried that and found it was too slow?
I'd like to add three statetments:
Manfred asks:
Yes, that's what I was thinking. You asked for dynamic scoping of procedure definitions, which I haven't seen in any other language. So I was saying that I'd be more inclined to do it in the way that I've seen in other languages (procedures are first class citizens). Then you could assign it to a variable and get dynamic scoping. To be clear, I'm not saying that I have time to do this, just that between the two choices, I'd prefer to do something mainstream. If someone else wanted to implement that, all the better.
We know first class functions here quite well from JavaScript. It would be a wonderful thing for FMSLogo. How to realize this and where to find the time for it remains a problem, of course.
The fact is that it was you - and not anybody - who kept this most important Berkeley Logo successor alive for so long, kept it reliable and well-documented and even improved it As limited as your time was - it worked. And this has been the basis of much of our work.
For more than a decade we have used FMSLogo as the basis of a truly great and successful school project - the central competence analysis of project SchuBS (a professional education project for young people which won more than one federal award.)
We have written pure FMSLogo-program-code up to more than 6000 lines without major problems, and we liked the reliability and versatility. So we did dozens of major amendments without difficulties. (By the way - I cannot do any C or C++ nor do I understand the operating system well. So far, we did only application programming.)
Unfortunately, the annual competence analysis of project SchuBS ended after 16 years in the pandemic due to a lack of funds. For next year, we have already prepared another large project (new methods in Bayesian statistical test theory) as replacement and programmed large parts of it (again, more than 3000 lines), which is now waiting in the pipeline. Our current project still includes Little Helper.
I think the reliable FMSLogo with its excellent all-in-one features and its wonderful list-processing is worth the efforts and the waiting - for the sake of the creatives of this world.
Addiditionally, I'd like to thank you for all the explanations araound turtles and their (rotating) bitmaps. Once we master them, a lot of good applications may be derived from them.
While the p5.js-solution is completely based on a html-canvas-flipbook, it has its own restrictions. It is perhaps too much flip-book based - which is good for the artists working with it but not for everybody.
The concept of turtles and their bitmaps on the other hand has its own use cases. You mentioned BITBLIT, which I did not find documented. Is it the same as BITBLOCK?
Anyway - now we've got enough stuff to experiment with and to find out what we can do with the FMSLogo-toolkit. We have at least 8 projects, each for an own coursebook and very interesting for students and teachers. The introductory tutorial will appear in summer (at the latest) - and our FMSLogo-amendment will have an own documentation. The coursebook series is planned to start in autumn - first in English, then in German and Chinese.
Manfred asked:
Yes, you're 100% correct. I meant BITBLOCK and BITBLIT is not a Logo command. BitBlt It's a win32 function that's not even what BITBLOCK uses, so I don't know why that's what came to mind.
As you guessed, my thinking is that, if clearing and redrawing the entire screen causes too much flicker, it might be possible to clear and redraw parts of the screen in rotation. Thinking more about it, even if it caused less flicker, I'd have to look at the Logo code to see if I'd really use it. BITBLOCK would be a bit clumsy, because you'd need to reposition the turtle to use it or have a different, hidden turtle on standby waiting to clear the part of the screen that another turtle draws.