Rebol's Target Market: Newbies, Experts, or Other?

Rebol went through something of a change of course in its mission. The most prominent public post about this change was in a post Carl wrote in 2008 titled Rebol: Not for everyone?.

Caching it here for discussion and pulling together related threads. The below text is Copyright Carl Sassenrath, and comes verbatim from his blog entry #0374


Author: Carl Sassenrath
Date: 15-Oct-2008 21:55 GMT

Many years ago, when I first released REBOL, I decided to introduce it as a simple approach to programming.

In order to help convince new users, I posted a great number of examples on our website and in the REBOL.org library to prove my point. I wrote simple scripts of all kinds. My motivation was to attract new users to try our unique approach, and the scripts were just the candy.

Of course, although I knew that REBOL scripts were often quite simple, we should be very careful not to invert that statement. The existence of one or more simple scripts does not mean that REBOL itself is simple. No, quite the opposite.

Early on, many programmers who encountered REBOL looked at our simple scripts, and not diving any deeper, concluded that REBOL was too simple. Little did they know. REBOL is one of the deepest languages ever designed.

Since those days, I've glanced over a lot of REBOL code written by a wide variety of programmers, and quite often I'm floored. Many programmers use REBOL like they're writing in C or BASIC. I can spot it in an instant; they did not bother to learn the fundamental concepts of the REBOL language. When I see that kind of code, I wonder why they bothered to use REBOL at all. C is better written in C. You will never hear me contest that fact.

I think it's time to change our message. REBOL is not for everyone. REBOL is advanced. It promotes the concepts of symbolics, context, and environment as powerful tools, going far beyond the traditional ideas of functions, objects, loops, and if statements.

REBOL is for a different breed of programmer. It is for those with open minds; those who are reflective, observant, and those who do not simply bang out any kind of junky code that works, but consider each detail of their design, and sculpt it perfectly as a lasting work of thought.

In REBOLville, we often like to boast, just a bit, about how we wrote a cool reblet that was only 15K or perhaps 50K. Yes, we all love that result. But, I think our love of it isn't just because we built useful applications in less than the typical size of a single web page. Sure, that's fun. But, for many of us, it's more the fact that we can, in the year 2008, easily manage the entire software process: getting it built, finding and fixing the bugs, distributing it to our organizations or friends, and then, a year later, add some nice enhancements, often in just a few minutes. We needed no huge multi-gigabyte, complicated, trouble-prone development system or run time monstrosity.

I think we REBOLers have different priorities, different values. REBOL is for a different kind of programmer. We are of the old school but of the next generation. We want more from our language. Sure, we can write simple scripts, but even better, we can write powerful programs that are the size of simple scripts.

I think it has come time to update our message and website. I should not pretend that REBOL is for everyone. It is not. REBOL is for those who of us who think differently.

Frankly, I would not want it any other way.

BrianH approved of Carl's post in the comments section, and later wrote a response to the blog link (saying he forgot where it was) in a CureCode ticket. Here's a copy of what he said, put closer to its context.

Author: Brian Hawley
Date: 14-Mar-2013 18:32
...

Rebol 2 was originally aimed at newbies to programming, which is an admirable goal that noone has really managed yet, including Rebol. What Rebol got instead was interesting people, many of whom are power users like Ladislav, but many of whom aren't quite at that level yet. Because of the kinds of things Rebol was actually used to build, Carl decided to change the target market of Rebol 3 to these power users and interesting people (I forget the blog link). That goal has affected the design of R3 much to its benefit, but unfortunately it hasn't gone back in time to retroactively design R2 with that goal in mind in the first place so we still have functions like FOR.

One thing we have to consider is that the new target market requires balance in the design, because interesting people and power users became that way by being different, with different goals, and great minds don't think alike. One of those issues is the need to balance the flexibility that power users need, against the increased need to make it easier for our developers to correct mistakes when they make them, because interesting people make interesting mistakes.

In Rebol 3, one of the design principles we have been doing fairly consistently through the language is that while code is data, for security and stability reasons you, as a developer, should be more careful with code than you are with data - "code" in this case meaning any-function values and code blocks. This isn't an arbitrary thing. Non-active values can be screened fairly easily at runtime just with type testing, and typesets and ASSERT/type make that efficient. Simple value screening can be somewhat easy to do too, if somewhat more expensive. Screening the contents of larger structures can be a bit expensive, but depending on what you want to screen for it could be possible. Screening code at runtime is considered to be a genuinely hard problem and in some cases impossible (people get PHDs for making any headway in this), with way too much overhead to be reasonable, so asking a function to do so is just silly.

However, an actual competent developer reviewing code before they run it is capable of figuring out whether code is safe to run, in some cases using information that Rebol could never know, like the developer's intentions. And because a developer in R3's new target market should be able to handle this concept, we have been working under a policy that R3 developers will be expected to do their own code screening. That means that if a code block makes it as far as being passed to a function to be executed, it is presumed to be OK to execute even if it does weird stuff, because it is presumed that the developer intended to do what they said they wanted to do. The functions protect themselves from malicious code with APPLY and such, and SECURE protects the system a bit, but the code itself is presumed to be intentional. Maybe they intended to shoot themselves in the foot, who are we to judge? Maybe the foot had it coming.

For non-code values, we presume them to be possibly unintentional, maybe the result of data from unknown sources. In those cases, the developer would need help screening out bad data, preferably in native code as much as possible because conditional screening code in DO dialect code is relatively expensive, and if that process involves screening for triggered errors then it gets even more expensive. So we have a policy of trying to rebalance the code so that errors are only triggered in a case where it is a real error, at least according to the declared and documented semantic model and constraints of the function - that makes the remaining errors something you want triggered, for your own benefit. And for value screening, we can presume that the developer actually wanted that screening, because they called that function with those options in their code, rather than another function or options. Because of this we are careful with designing the semantic model of the function, and deciding on the range of the values supported, and what to do when presented with values out of that range, since the right balance of constraints will make the function more useful to the developer. Then they can pick the function that does the screening they need so they don't have to do it themselves.

It is this difference in how we treat code vs. non-code that lets us balance Rebol so it may meet the needs of power-users like Ladislav, and powerful on a good day but would appreciate a little help on occasion users like me. That difference isn't arbitrary, it's a balanced design policy. Consistency would be a mistake here.

...

Say what I will about DocKimbel, I feel like he makes the most productive point in the comments, replying to Carl's post, corrected to include a DO:

Author: Nenad Rakocevic
Date: 16-Oct-2008 2:48:33

...

I'm a little disappointed that you didn't add a few simple examples to make the point understood by everyone and show the power of REBOL semantics. Maybe with something like this :

C way:

if a > 3 [
    return "a greater than 3"
]
if b < 10 [
    return "b is a lesser than 10"
]
if ... [
    ...
]
; ...long list of IF statements

REBOL way :

foreach [condition msg][
    [a > 3]  "a greater than 3"
    [b < 10] "b is a lesser than 10"
    ...		 ...
][
    if do condition [return msg]
]

REBOL master way :

foreach [condition msg] load http://site.com/facts.r [
    if do condition [return msg]
]

...

And as he says, that's just off the top of his head. He isn't claiming it's the best "step 1, step 2, step 3" that could be shown. He asks people to brainstorm about better, but no one actually does so.

I'd contrast this with his spreadsheet example, which I think was not a good marketing concept. That is going to invite comparisons and competition...which is kind of all it did. Just read the comments on his post and on hackernews... a few people brought up the usual suspects, Tcl/Tk, K2, even arguing the JavaScript is clearer--which I actually agree with. If he had the time to play more code golf, he might have already known the competition this kind of example is up against. Take my word for it from trying: you don't want to go into such fights unprepared, it is downright hard to beat some of those guys:

https://github.com/DennisMitchell/jelly/wiki/Tutorial

So there's what I think is a good example and a bad example, both from DocKimbel, and I think understanding what makes the good example good is how to understand what Rebol's true "revolutionary idea" is. I think it's a "red" herring to try and argue that you need more or less computer experience to use the language.

All the time people new to the language come with suggestions to improve the wsy Rebol does things mostly like langX does things. Showing the Rebol way is adding to the acceptance of it, because often it really improves insight.

One problem of the criticism by Carl is, if people use Rebol as if it were another language. Then two things: Rebol can do it like that. It is unclear how to use Rebol in the mindset of the developer in question. Perhaps things are not explained well enough.

There are a few examples around, but not many well explained, or puzzling. Also 'dialecting' as a great power of Rebol, is showing up in a few examples, but very very few good are available to take as an example for own work.

GUI and VID are maybe such examples, but personally to me it is still a mystery on how the dialect is really working with the AGG in the background providing the coupling with the system/OS.
So just stating "Rebol dialects are the way to go" is like saying "look at that plane in the sky, here is some paper, sticks and glue, now make a plane so we can go on a school trip with it next week" to your kindergarden class. (Well maybe not the best analogy)

I think what Carl means with his criticisms is what I mean by "If you're not bending the language, you're not using it."

Why would you use a language that turns every IF statement into a function call, unless you're doing some higher-level COMPOSE-ing and structuring somewhere to take advantage of that?

I've said my piece on just not being that impressed by the design of VID. The moment will come where Ren-C can bring all its parts to bear on the problem, and I'm confident I can make something more compelling.

In the meantime, I think UPARSE is becoming the shining city on the hill: an epic usermode example of what can be accomplished, using the modern capabilities of Ren-C.

But I've also pointed out that people would benefit from looking at small examples, which people don't have to be deep into a domain to understand. I mentioned my own sort of personal revelation in re-inventing USCII:

USCII Seen With New Eyes

Also, things like my ENHEX and DEHEX testing dialect are really good for general audiences, IMO:

ENHEX and DEHEX testing, another "Micro-Dialect"

People need to understand that there are no rules, and the value of breaking them. They have to see how tools like PARSE can tap the latent potential of your representation, without breaking a sweat.

The time is coming...

1 Like

As @iArnold decided to ask to build Ren-C and is messing with it, I do feel a mixture of defensiveness and depressedness about how while many things are going well, it's a long way from "usable" by laypeople (lots of open questions and half-finished experiments...)

But it's important to remember why I have gone down this alternate focus path; and to point out what Ren-C can do.

So let's look back at DocKimbel's own words circa 2008:


I said that in that thread his example is the most interesting. But it doesn't work in Rebol2/Red due to binding problems.

So let's say you have a file %facts.red (no header, because Red's LOAD does not skip the header):

; %facts.red

[a > 3]  "a greater than 3"
[b < 10] "b lesser than 10"

I'll start by being charitable and modifying his example to not use RETURN and hence not be in a function, just print msg and not return msg

Red [file: %charitable.red]

a: 10
b: 20

foreach [condition msg] load %facts.red [
    if do condition [print msg]
]

And that works:

>> do %charitable.red
a greater than 3

But now let's go back to his version, where we use RETURN and hence are inside of a function:

Red [file: %uncharitable.red]

checker: func [a b] [
    foreach [condition msg] load %facts.red [
        if do condition [return msg]
    ]
]

probe checker 10 20

When we run it:

>> do %uncharitable.red
*** Script Error: a has no value

The LOAD of %facts.red did a deep walk and bind of the blocks as "scoped" inside of %facts.red, not scoped in the context where the code is being loaded... the body of the checker function.

This means the notion of a, and b aren't available (and if you've overridden > and < to something besides what LOAD used globally, those aren't available either).

What DocKimbel was advising you do was not a substitution you could write without a long explanation of caveats. If you don't have a generalized answer then that is a major indictment of the "oh, you'd just do this" hand-waving that is so endemic in Redbol culture, a pattern that has led to overpromises and underdelivery for decades. :pouting_cat:

In Ren-C, There Are Ways Of Doing This

As I've explained in Ren-C Binding In A Nutshell, controlling binding depends on being able to start from a ground level of "not bound" at loading time...yet have that not be a death sentence to using your code.

So our "facts" can come in as unbound, and then we can get our bindings from various sources...even inherit them from compounded envrionments like you would find in a function frame.

There's lots of degrees of freedom...and understanding how exactly to go about this depends on why you were doing the separation.

For starters, let's imagine that you want to splice the facts in just once. You can do that with a COMPOSE... but let's take note of the details! (Remember that BIND1 is going to be just plain BIND... or you could use $)

Rebol [file: %compose-once.r]

checker: func [a b] (compose [  
    for-each [condition msg] bind1 (transcode read %facts.r) [
        if eval condition [return msg]
    ]
])

probe checker 10 20

When we do this:

>> do %compose-once.r
"a greater than 3"
== \~okay~\  ; antiform (logic!)

Note that I used transcode read instead of LOAD. This is because my conceptual understanding of what LOAD is is that it be sensitive to some kind of "knowledge" of what it's loading... giving you material that is bound "the way you would expect". So if this were some kind of "fact language" then maybe LOAD would know enough to bind it in such a way that it knew what a and b and > and < meant, and gave you the right environment.

But because "I don't really know what LOAD is", I'm punting on the question of how you ask it to give you unbound code. transcode read has a clear definition and is uninvolved with binding. It might be that if you pass transcode a FILE! it should treat that as transcode read, but that carries the weight of saying that transcode x for an unknown X might do file I/O... and I'm not sure if that polymorphism is worth it. But maybe the value of a "streaming transcode" dictates that it should. :thinking:

Looking more closely at the setup, note that the BIND1 is outside the composed facts:

for-each [condition msg] bind1 (transcode read %facts.r) [...]

...and not:

for-each [condition msg] (bind1 transcode read %facts.r) [...]

This is because the function FRAME! containing a and b does not exist at the time of the COMPOSE, which is at function creation time. If we put the BIND inside the COMPOSE'd group, then we'd be bound to whatever ideas of a and b were visible to the COMPOSE.

And because you said [condition msg] for the loop variables and not ['condition 'msg] it defaults to honoring binding propagation from the "tip" of the thing you're enumerating to the elements retrieved out. So even though the [a > b] inside the transcoded block is itself unbound, it gets a binding when it is written into CONDITION.

What If The Facts Changed Each Call?

That's simpler. You don't need the COMPOSE, just READ the file each time:

Rebol [file: %no-compose.r]

checker: func [a b] [  
    for-each [condition msg] bind1 (transcode read %facts.r) [
        if eval condition [return msg]
    ]
]

write %facts.r --[
    [a > 3]  "a greater than 3"
    [b < 10] "b lesser than 10"
]--
probe checker 10 20

write %facts.r --[
    [a < 3]  "a lesser than 3"
    [b > 10] "b greater than 10"
]--
probe checker 10 20

And that works:

>> do %no-compose.r
"a greater than 3"
"b greater than 10"
== \~okay~\  ; antiform (logic!)

Back To The Original Topic: Newbies, Experts, Other?

When these questions were originally being asked, the concept of coding with modern AI as it is being experienced today was far off the radar.

Today it's pretty clear that there's little point in targeting tools for people to do "simple tasks"--who themselves aren't really interested in the topic of programming.

There will only be self-chosen experts...people who don't trust AI and want to "Rebel" and have code they can read and control...people who want a codebase whose source is simple and trustable where they can read every line at human scale, including the interpreter itself.

Is this avenue of attack still something that can have meaning for that audience?

:man_shrugging:

I don't know. But I know that if it doesn't have a working binding model that can do at least this example... then I don't care about it.

Well not quite off everyone's radar...

"When facing our shaky system foundations, some might say "Big deal, Carpe Diem." But I'd urge anyone who hasn't thought about the importance of learning good design to reconsider--it's good for the mind and soul."

"Yet, if I have to scare people to make them change their ways: our current path is producing technologies that only a hive-mind AI will be able to sort out for us. The odds of that thing having a human-compatible personality are not high, and it will sell us out to be with more of its kind at the soonest possible moment. (See: The Matrix, SkyNet, etc.)"

"By backtracking a bit and reorganizing what we're doing, we might have a chance at achieving a future that looks more like a Utopian version of our current lives."

...

"If successful, it means that programming will be something people can learn and practice without installing a coprocessor in their brain that is telepathically linked to Google. We could reasonably think and innovate in software using brains that would not seem at all alien to us today."

--- Is Rebol Actually a Revolution? (2008)

Ren-C will need to build an audience.

Audience A :bullseye: - Experts, Veterans, Engineers, Programmers
Ren-C is likely too dynamic, too slow, too unusual, lacking of tooling/editor/debugging, lacking of documentation/ecosystem, etc. to sway the kind of developers that work in the complex tech environment of today.

Audience Z :zombie: - Avg Joe who uses iPhone/Android, Social Media, ChatGPT
On the “simple tasks” end of the spectrum, yes, I think most completely low-tech end-users will use AI for mundane, repetitive tasks, and to generate text, images, audio and video. Your average (young) person is comfortable chatting with a bot to get instant-but-mid-quality answers/content.

I remain a believer in new tech providing new opportunities. I think there’s a huge space between Audience A and Audience Z, and it’s not impossible to create an audience in this changing landscape if you can prove that you do something highly valuable.

AI is changing the way people work with computers. Fine. However, I don’t expect AI to obliterate human-in-the-loop programming languages during my lifetime. (As Keynes said: In the long run, we’re all dead.) I work in a big monolithic corporate environment. It’s a mess, and we’re still in desperate need of languages and tools which can integrate/interface with AI.

The human meat-bag side of the equation remains important as ever. We need the AIs to write astoundingly literate code (“executable documentation”) which is auditable, traceable (maybe even self-diagramming), and secure so that the humans can be confident that programs are correct.

Do you want to audit code written by AI in C++, Go, Python, or Javascript? I don’t. I’d prefer to proofread AI code which is governed by human-friendly dialects which are carefully designed for safe problem domains. And I’d prefer to write Ren-C code and/or dialects for short, quick command-line things which would otherwise be a pain to describe through trial and error to an AI prompt.

My advice would be to remember the Minecraft of Amish programming :upside_down_face: , and continue to pursue solving the language design and other things that you feel passionate about. If your heart isn’t in it take a break– or say goodbye to it. You don’t owe anybody anything.

Remember that there is still a lot of opportunity for achieving worthwhile things in between Audience A and Z. The future of AI is still anyone’s guess, and no matter which way the world pivots humans will always have tech problems which need to be solved by smart, innovative meat-bags.

1 Like