I was working with the httpd server, when I tried to write some code that would respond with ever-longer strings on each request. If you don't see what's wrong with it, don't feel bad:
import %httpd.reb n: 0 str: "HighCodepointCat(😺)" wait srv: open [scheme: 'httpd 8000 [ n: n + 1 expected: copy str loop n [append expected expected] render expected ]]
What's wrong is that inside the scheme, your code is being wrapped inside a FUNCTION, where locals gathering applies . This means the n: 0 that happens before the open scheme is lost; by virtue of being a SET-WORD! the n: n + 1 tries to add to an uninitialized local variable. Bad Mojo.
I'm more certain than ever: we need LET, and it needs to be implemented via "virtual binding".
Yes, yes...I know, I know...I've talked a lot about virtual binding for a couple years, but haven't managed any flash of inspiration for a performant way to pull it off. The writing is on the wall, though. We might just have to bite the bullet and accept a slow-ish solution for starters, then wing it with optimizations as more experience is gathered.
Then the problem I talk about with httpd goes away, along with all the ancillary problems I mention in the linked discussion.
Interestingly: FUNC and FUNCTION could then be synonyms
When this hit me, I had to think to myself: "Why would they be anything else -but- synonyms?"
(Code golfers and other weirdos can invoke auto-gathering and get their ridiculously bloated frames via some other notation or refinement.)
It was this same thought that drove me to believe EVAL and EVALUATE should not be distinct either.
That made me wonder if this was some kind of broader philosophical concept for the language. Don't make abbreviated forms of things act differently than their unabbreviated forms. Use abbreviations for shorthands only.
This kind of thinking would rule out PRIN being different from PRINT (if it existed at all). I detest PRIN, and think most people using it would be better off doing a PRINT COLLECT. Legitimate usages look fine as WRITE STDOUT, in the few cases they actually arise.
prin "Values: " data: reduce [1 + 2 3 + 4] prin ["[" space] for-each item data [ prin @item prin space ] prin "]"
print collect [ keep ["Values:" space] data: reduce [1 + 2 3 + 4] keep ["[" space] for-each item data [ keep @item keep space ] keep "]" ]
It might seem less efficient to build the block. But on a fully abstract machine, how would you know that? What if each I/O request incurs some overhead, and making only one I/O request would thus be faster?
...channeling Paul Graham for a moment...
I told a story on seeking "Timelessness" in my conference talk, and it kind of dovetails with what he says in his 100-year-language essay:
I can already tell you what's going to happen to all those extra cycles that faster hardware is going to give us in the next hundred years. They're nearly all going to be wasted.
I learned to program when computer power was scarce. I can remember taking all the spaces out of my Basic programs so they would fit into the memory of a 4K TRS-80. The thought of all this stupendously inefficient software burning up cycles doing the same thing over and over seems kind of gross to me. But I think my intuitions here are wrong. I'm like someone who grew up poor, and can't bear to spend money even for something important, like going to the doctor.
Some kinds of waste really are disgusting. SUVs, for example, would arguably be gross even if they ran on a fuel which would never run out and generated no pollution. SUVs are gross because they're the solution to a gross problem. (How to make minivans look more masculine.) But not all waste is bad. Now that we have the infrastructure to support it, counting the minutes of your long-distance calls starts to seem niggling. If you have the resources, it's more elegant to think of all phone calls as one kind of thing, no matter where the other person is.
There's good waste, and bad waste. I'm interested in good waste-- the kind where, by spending more, we can get simpler designs. How will we take advantage of the opportunities to waste cycles that we'll get from new, faster hardware?
The desire for speed is so deeply engrained in us, with our puny computers, that it will take a conscious effort to overcome it. In language design, we should be consciously seeking out situations where we can trade efficiency for even the smallest increase in convenience.
I Propose Abbreviations As Synonyms For What They Abbreviate
What people do in their own code is up to them. But I'm feeling that what's in the box and tutorial examples should stick to this principle.
OPT: :OPTIONAL LIT: :LITERAL ; ...or `LIT: LITERAL: :LITERALLY` ?
I like what this is pointing to, and now that I've had the thought I can't see FUNC and FUNCTION any other way.