
Wren: A classy little scripting language - StylifyYourBlog
http://munificent.github.io/wren/index.html
======
captaincrowbar
For those who don't know, this is from Robert Nystrom, author of Game
Programming Patterns:
[http://gameprogrammingpatterns.com/](http://gameprogrammingpatterns.com/)

[https://news.ycombinator.com/item?id=7634734](https://news.ycombinator.com/item?id=7634734)

------
tonyg
I like the idea very much, and the brevity and clarity of the implementation
is pleasant. However, there are a few problems with it:

    
    
      \\/"-
       \_/   wren v0.0.0
      > var F = new Fn { | x | F.call(x + 1) }
      > IO.print(F.call(10))
      Segmentation fault
    

This shows two things. (1) it's not yet a "safe" language implementation; (2)
it doesn't support proper tail calls. Both are fixable, of course, but the
lack of proper tail calls is a Bad Language Smell.

Its syntax is also a little strange. The following isn't accepted by the
parser:

    
    
      var F = new Fn { | x | if (x == 0) { return x } else { return F.call(x - 1) }}
      IO.print(F.call(10))
    

but the same file with extra newlines is accepted just fine:

    
    
      var F = new Fn { | x |
          if (x == 0) {
             return x
          } else {
             return F.call(x - 1)
          }
      }
      IO.print(F.call(10))
    

It also makes me a little sad that

    
    
      var F = new Fn { 0 }
    

returns 0, while

    
    
      var F = new Fn {
          0
      }
    

returns null.

~~~
munificent
> (1) it's not yet a "safe" language implementation;

Not yet, but it's getting there! I have to fix this:

    
    
        // TODO: Check for stack overflow.
    

On line 335 of wren_vm.c. The actual fix is pretty straightforward. You just
store the maximum stack height with each function and check that that doesn't
overflow on a call. I just haven't gotten around to it.

Wren should be pretty good about most other boundary case behavior. If not
(and like this issue too!) it's a high priority bug. Your scripting language
shouldn't crash!

> (2) it doesn't support proper tail calls. Both are fixable, of course, but
> the lack of proper tail calls is a Bad Language Smell.

That's correct. I have implemented TCO before. Wren's predecessor Finch
supported them. Fibers in Wren already support an analogous feature.

My current thoughts are that I likely will support this, but it will be
explicitly opt-in. Instead of having the tail call automatically be detected
and eliminate the parent stack frame, you'll have some specific syntax to say
"this is a tailcall".

This is for two reasons:

1\. Most of the time, having a useful stack trace is really handy for
debugging. For better or worse, stack traces are a standard tool for most
users to understand when their code does something wrong.

Eliminating _all_ tail calls hurts this with little benefit in the majority of
cases where you aren't doing any recursion (mutual or otherwise) and will
never blow the stack.

Of course, you can do clever things to regenerate stack traces while still
doing general TCO, but that adds a lot of complexity and simplicity of
implementation is an important feature.

2\. With a language that has a non-sexpr syntax, it can be very hard for a
user to tell which call actually _is_ the tail call. Consider something like:

    
    
        {
          return (foo.bar + !baz).call ? some.thing : other / wise
        }
    

Can you quickly identify if this code won't blow the stack or not? If a user
comes along and makes some tiny change to that statement, can they be
confident their program won't start failing on larger inputs?

Given that, I think it's good to visibly call out "Hey, there's a tail call
here. It's important!" in the source code. I'm not sure what the syntax will
look like yet, but that's my intent.

    
    
        var F = new Fn { | x | if (x == 0) { return x } else { return F.call(x - 1) }}
    
    

Designing a syntax that's simple, expressive, and beautiful is tricky! Coming
up with one that's easy to compile with a single pass compiler is even more
tricky.

In this case, because you don't have a newline after the "|", it is looking
for an expression body. "if" is a statement, not an expression. There's a
bunch of ways this could be improved:

1\. Certainly, the error message should be better!

2\. We could make "if" an expression. We could make everything an expression
for that matter, though there's some pros and cons there.

3\. If could allow statement bodies in single-line functions.

> but the same file with extra newlines is accepted just fine:

Yup. This is probably the most unusual corner of Wren's syntax. It's
documented here:

[http://munificent.github.io/wren/syntax.html#blocks](http://munificent.github.io/wren/syntax.html#blocks)

The constraints I'm working with are:

1\. I wanted a terse way to define single-expression members and functions
that return their result.

2\. I'm not a fan of implicit returns in larger bodies. I don't like the idea
of methods implicitly leaking the result of their last expression even when
that isn't intentional, and I think it tends to lead to less efficient
bytecode.

So I tried to come up with a specific syntax for a single-expression body.
Other languages use stuff like "=>", but I wanted to try to not add more
punctuation.

Since newlines are already significant in the language, I figured I'd try
using the newline after "|" or "{" as the signal.

So far, I personally like how it feels, but feedback from others like you is
definitely helpful. If it rubs a lot of people the wrong way, it's easily
changed.

~~~
JadeNB
> 2\. We could make "if" an expression. We could make everything an expression
> for that matter, though there's some pros and cons there.

I'm not sure if this is the place for such a far-reaching discussion, but I've
never understood this point. What are the cons to making everything an
expression?

~~~
munificent
Until recently I was firmly in the "statements are evil" camp. Now my
perspective is a bit more nuanced. There are two facets to "everything is an
expression":

1\. Any grammatical production can be used in an expression.

2\. Function/method bodies implicitly return the result of the last expression
they contain.

I really like #1, though even expression-oriented languages limit this.
There's still something akin to "operator precedence" at the "statement-list"
expression level. If, for example, you look at Ruby's grammar, you'll see it
has productions called "statements".

This is to rule out totally bizarre things like:

    
    
        1 + while (foo) { ... }
    
        for (for (for (...) {}) {})
    

So, even if you treat everything as an expression, there are still some
limitations as to where different grammatical productions can appear.

In practice, I think the main thing you gain (in a language with an
imperative-style syntax like Wren, Ruby, etc.) is the ability to have the
right side of a return or assignment be a branching statement. Stuff like:

    
    
        var fizzBuzz = if (n % 15) {
          "FizzBuzz"
        } else if (n % 5) {
          "Buzz"
        } else if (n % 3) {
          "Fizz"
        } else n
    

The other statements are less useful. I'm not even sure what the result of a
looping expression should be, but I'm certain that I don't like CoffeeScript's
answer (an array of all of the elements, which often gets discarded!). Break
and return statements have no useful results. Variable declaration statements
make it really hard to reason about scope when used in the middle of an
expression.

All this means that I think loosening up the grammar to make _every_ statement
an expression is mostly only useful to make _branching_ an expression.

The other half is having functions implicitly return the result of the last
expression. I really like that in some functions for brevity, and _really
dislike_ it in others. This may not be rational, but creeps me out that lots
of Ruby methods just leak random values.

For me, I'd rather have an explicit form for bodies that implicity return
their result and have the default be to not do that. So that's what I did for
Wren. A single-line body implicitly returns its result, but a multi-line one
does not:

    
    
       class Person {
         name { "Fred" } // Implicit return.
    
         sayHi {
           IO.write("Hi, I'm Fred!")
           // Returns null.
         }
       }
    

I like this more than always having an implicit return, so this addresses
point #2 above. I'm not opposed to allowing branch statements to be
expressions, but I worry that the confusion it causes may outweight the
benefit, so I conservatively left it out for now.

Having a statement/expression distinction also makes the bytecode compilation
a bit simpler. It's easier to tell which things emit values and which don't,
but that's not hard to fix.

~~~
jpfed
> I'm not even sure what the result of a looping expression should be

>Break and return statements have no useful results

The result of a looping expression could be specified by its break!

    
    
        var myNeedle = foreach(var maybeNeedle in myHaystack) {
            if (maybeNeedle.isTheNeedle()) break maybeNeedle;
        }
        if (myNeedle != null) print("I found " + myNeedle.toString());

~~~
twic
I quite often find myself writing code like (in Java):

    
    
      Fruit edibleFruit = null;
      for (Fruit f: basket) {
        if (f instanceof Banana) {
          if (!f.isDiscoloured()) {
            edibleFruit = f;
            break;
          }
        } else {
          if (!f.isMouldy()) {
            edibleFruit = f;
            break;
          }
        }
      }
    

And getting rid of the nasty assign/break pairs by extracting a method:

    
    
      Fruit edibleFruit = edible(basket);
    
      Fruit edible(Collection<Fruit>: basket) {
        for (Fruit f: basket) {
          if (f instanceof Banana) {
            if (!f.isDiscoloured()) return f;
          } else {
            if (!f.isMouldy()) return f;
          }
        }
        return null;
      }
    

But your idea would let me clean up without having to extract a method (here,
in a hypothetical Java-with-value-bearing-break):

    
    
      Fruit edibleFruit = for (Fruit f: basket) {
        if (f instanceof Banana) {
          if (!f.isDiscoloured()) break f;
        } else {
          if (!f.isMouldy()) break f;
        }
      }
    

You need to have a story about what happens if there isn't a break - if the
loop exits normally. You could implicitly return null, but that's a terrible
idea. Better would be to require else clauses on value-returning loops (a bit
like the else clauses that Python allows on try blocks):

    
    
      Fruit edibleFruit = for (Fruit f: basket) {
        if (f instanceof Banana) {
          if (!f.isDiscoloured()) break f;
        } else {
          if (!f.isMouldy()) break f;
        }
      } else null;
    

Yes, i'm still returning null here, but at least i have to do it explicitly,
which makes me feel bad about it and think about finding a better alternative!

------
abcd_f
> _The codebase is ... lovingly-commented_ [0]

For what it's worth, I absolutely _love_ reading this sort of spanning
descriptive comments. It makes the code that much more interesting and gives
it a healthy dash of personality.

I used to work with a guy who'd have header files start with pagefuls of
comments with ASCII diagrams, book references, complete design rationale and
what not, only to follow with just a handful of rather terse declarations,
which still would be immediately clear thanks to the preceding narrative. That
was so damn beautiful.

[0]
[https://github.com/munificent/wren/blob/46c1ba92492e9257aba6...](https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433)

~~~
icefox
The main page fails to communicate how the language is going to solve a users
problems. The main page (which is what most people will only see) list the
following features:

Wren is small. Wren is clean. Wren is fast. Wren is class-based. Wren is a
scripting language.

If something is big, slow and message I don't care if it solves my problem
when nothing else can. The only bullet point that comes close is the one
talking about it being 'class-based', but I almost never hearing someone say
"moving the code to classes will solve this problem". If that it is class
based why would I use it over (as mentioned in the second sentence) Lua (or
any one of the scripting "languages" that are just javascript in tiny form
where I don't have to do any learning)? It seems like an easy pass for the
majority of people that only read the main page.

What problems do users that need an embedded scripting language have? Just
guessing, but probably #1 is the difficulty of integrating it into their
existing project (and ease of extendibility with my app). Followed by language
compatibility, control over garbage collection, and docs so I can spend more
time on my app and less time mucking with the scripting language. I am
guessing that something like these are the pain points that the main page
should talk about.

~~~
munificent
I wrote a long reply, but HN apparently thinks I'm a spammer on this thread
and ate it. :( Let me see if I can recall:

> If something is big, slow and message I don't care if it solves my problem
> when nothing else can.

This is true of a general purpose language. I'm sure most Ruby or Python users
couldn't tell you the first thing about how big or complex MRI or CPython is.
As long as it works, it works.

Embedded languages are a different beast. When you drop something like Lua or
Wren into your application, you're taking a direct dependency on its source
code. You will end up stepping into in your debugger, reading its comments,
etc. You will be shipping the language implementation itself physically with
your application.

When that's the case, having a small, clean implementation becomes a very
important feature.

> The only bullet point that comes close is the one talking about it being
> 'class-based', but I almost never hearing someone say "moving the code to
> classes will solve this problem".

Syntax is about usability, not utility. It's almost never a question of "Can I
do this using classes." Everything is Turing complete, so you _could_ use
Brainfuck as your scripting language. The key question is, "Is it easier, more
enjoyable, and less error-prone to use classes?"

If you're writing OOP-style code, which people increasingly do to script apps,
I believe the answer is yes.

Here's an example of that kind of object-oriented programming in Lua:

    
    
        Account = {}
        Account.__index = Account
    
        function Account.create(balance)
           local acnt = {}             -- our new object
           setmetatable(acnt,Account)  -- make Account handle lookup
           acnt.balance = balance      -- initialize our object
           return acnt
        end
    
        function Account:withdraw(amount)
           self.balance = self.balance - amount
        end
    
        -- create and use an Account
        acc = Account.create(1000)
        acc:withdraw(100)
    

Here's the same example in Wren:

    
    
        class Account {
          new(balance) { _balance = balance }
          withdraw(amount) { _balance = _balance - amount }
        }
    
        // create and use an Account
        var acc = new Account(100)
        acc.withdraw(100)
    

I believe this is a real productivity and maintainability improvement, and
productivity is exactly what scripting languages are for.

> Just guessing, but probably #1 is the difficulty of integrating it into
> their existing project (and ease of extendibility with my app).

Yup! That's also a key requirement (and one I still have a lot of work to do
on.)

~~~
j_s
I believe OP was pointing out an issue with the marketing... just copy _a
language as simple as Lua, but that feels natural to someone with an OOP
background_ (or something similar) to your first bullet point!

Edit: looks like your original comment made it through, and this repeat may
best be deleted. Keep up the good work.

~~~
icefox
Yeah I was really just trying to point out that the marketing on the main page
can be improved. I get that OOP can be a selling feature, but the other four
not so much. Using the main page to talk about how great it does integration,
how great the docs and examples are, and the API compatibility story are all
things that would be better for convincing users to go to the next page. Using
the funnel model how many users only viewed the main page and never went
further?

~~~
munificent
> Yeah I was really just trying to point out that the marketing on the main
> page can be improved. I get that OOP can be a selling feature, but the other
> four not so much.

It's a totally fair point.

One thing I'm trying to keep in mind is who I'm marketing _to_. Right now,
since Wren is so young, the people whose attention I want are not end users.
They'd have to be half crazy to use Wren in its current state in a real
application.

The people that will take an interest now are those that are keen on new
languages for their own novelty's sake, or that are interesting in
contributing to Wren itself. That's the audience I had in mind, and I think
the bullet points make a bit more sense when you consider that.

Definitely, when Wren gets more mature, it makes sense to refocus the initial
verbiage on what it can do for and end user.

------
pierrec
Seems like a very cool language. Fibers are really just coroutines, right? The
`Fiber.run` method allowing you to completely wreck the stack seems a bit
dangerous at first glance.

The everything-is-a method approach is also really neat. For example, it's
neater than C#'s half-arsed approach where you can have public fields but it's
not recommended. However, I find there should still be an easy way of creating
public properties. It's useful when all you want is a structure holding a
bunch of values instead of a full-featured class. From what I can see, the
shortest way of creating a public property in Wren seems to be:

    
    
      class Cat {
        new { _name = defaultName }
        name { _name }
        name=(value) { _name = value }
      }
    

That can be a lot of boilerplate, especially when you need lots of public
properties. But that's just a minor nitpick, of course. I'm looking forward to
actually trying this language, but I'm not sure about its level of
completeness right now. It seems like everything is pretty complete, apart
from some parts of the documentation.

~~~
munificent
> Fibers are really just coroutines, right?

Yup! I picked "fiber" mainly because it's shorter.

> The `Fiber.run` method allowing you to completely wreck the stack seems a
> bit dangerous at first glance.

In most cases, you'll use "call", but "run" is the fiber equivalent of tail
call elimination.

> However, I find there should still be an easy way of creating public
> properties.

I'm trying to keep things minimal, but, yes, I'll likely add something for
that. Wren grew out of a prototype-based language called Finch and the latter
has "property definitions" that let you define a private field and accessor in
one go:

[http://finch.stuffwithstuff.com/objects.html](http://finch.stuffwithstuff.com/objects.html)

> I'm not sure about its level of completeness right now.

A lot of language features are implemented and everything that's implemented
has pretty solid tests. There's still a bunch of more minor stuff to do, but
what it really lacks is real-world usage.

I've been hacking on it in isolation (because implementing the language itself
is the real fun part for me), but an embedded scripting language needs to be
embedded in some real apps to get the critical feedback needed to make it
useful.

To make some progress there, I'm starting to hack together a little game
engine using Wren (think something like Löve2D), but I haven't put much time
into that yet.

------
untothebreach
I love munificent's opinions on programming langugaes (wish he'd never given
up on magpie...), and I can't wait to try this one out.

Unfortunately it doesn't build under GCC on linux right now, so use clang if
you want to try it out.

~~~
munificent
> Unfortunately it doesn't build under GCC on linux right now, so use clang if
> you want to try it out.

Can you file a bug? I know another user ran into some problems with this too,
but I thought we'd flushed them all out.

~~~
untothebreach
Bug filed and PR sent! :)

~~~
munificent
Merged! BOO-YA.

------
phyllostachys
I'm wondering how munificent feels about Squirrel[1]. It seems like Wren is
looking to fill the same niche that Squirrel fits. So I guess my question is,
how are they different, or, how is Wren better?

[1] - [http://squirrel-lang.org/](http://squirrel-lang.org/)

~~~
munificent
This is a great question! I probably can't do the answer justice in a HN
comment, and I don't know Squirrel as well as I'd like to, but here's some
random thoughts.

At a high level, Wren and Squirrel have a lot of overlap. They're both
dynamically-typed embedded scripting languages with an eye towards games and a
syntax that tries to look more familiar to someone from the C tradition.

Some differences are:

\- Wren is much younger. That means it's much less mature, but it also has
less baggage and cruft.

\- Squirrel is a good bit more complex than Wren in general. I'm trying really
hard to keep Wren small and simple and have a minimal set of orthogonal,
combinable features. Squirrel has a larger baked-in feature set.

This means squirrel sometimes has multiple ways to accomplish the same goal:
generators and threads, classes and tables, etc. With Wren I'm trying to get
as much mileage from as few features as I can. (For example, Wren uses fibers
for error-handling.)

\- Squirrels tables are pretty similar to JS objects and Lua tables, so some
of Squirrel has that prototype-y feel. That's kind of cool, but it also brings
in some stuff I don't like. For example, I think Squirrel has the problem that
Lua and JS have where "this" may not be bound to the object that you think it
is because it doesn't have a real method/function separation. In Wren, "this"
does exactly what you want, even in closures.

\- Squirrel is written in C++. Wren is pure C99.

\- Squirrel is primarily ref-counted with an opt-in mark-sweep GC (to clean up
cycles, I assume). Wren is straight mark-sweep (though I anticipate going to
incremental at some point for latency).

\- Squirrel uses 8-bit or 16-bit character strings. Wren uses UTF-8 (or, at
least, it will as that gets fleshed out more).

If you want something stable and usable today with all the features you could
want, Squirrel is probably a good fit. If you're looking for something that
feels a little more minimal and hews to a more modern aesthetic, that's what
I'm aiming for with Wren.

~~~
phyllostachys
> Squirrel is written in C++. Wren is pure C99.

Awesome. My primary interest in Lua and Squirrel was to embed a scripting
language in a C environment on a microcontroller. This is perfectly doable
(and has been done before) but Lua is particularly attractive because it is
written in ANSI C.

I think it is interesting how similar embedded systems devs and game devs view
their code with an eye towards performance and size. It is nice because
embedded systems typically don't use newer languages and the developers tend
to never move away from C as the language of choice (sometimes it seems like
everyone is stuck in the 80s or 90s).

~~~
munificent
I believe (but have no proof) that Wren is more amenable to running on a
microcontroller than Lua or Squirrel. Wren has a more compact representation
for instances of classes and simpler/faster method dispatch. It's still duck
typed, but it gets closer to statically-typed language where an instance is a
simple in-place array of fields and field access is just a pointer offset.

------
ac2u
Not often I find a C project that can compile to JS via emscripten without too
much work.

[http://i.imgur.com/XMZE04i.png](http://i.imgur.com/XMZE04i.png)

If it takes off for game engines then it could be used for scripting
canvas/webgl games too.

~~~
munificent
Neat! I'd wondered about that but didn't have the time to try.

~~~
ac2u
It more or less worked out of the box with latest emscripten, the only thing I
replaced was the call to getline with an inline version pulled from google
code.

More work needed to make the REPL more user friendly in HTML (emscripten uses
browser prompts to get input when you follow basic instructions to output to
HTML but could tweak to have a more user-friendly REPL experience).

Additionally you can do things like the what has been done with the emscripten
port of Lua and supply wren with a bridge interface to work with the DOM
directly. From that it's a short path to having

<script language="text/wren"> with a bootstrap script to parse them out and
feed to the wren engine :-)

Of course if it were as easy as typing this out i'd be doing it already!

------
jayvanguard
My usual reaction to these things is "does the world really need another
language/framework?"

But this is actually a cool little language with well thought out features. I
can see it being very useful for embedding.

------
Havvy
"There are lots of scripting languages out there, but many have unusual or
non-existent object models. Wren places classes front and center."

Does it make me unusual to find classical object models shouldn't be
considered a 'usual' object model?

~~~
nly
What would you consider 'usual'? Classification as a cognitive process can be
seen throughout science and engineering.

~~~
Havvy
I'd consider structs that implement various traits (to use Rust's terminology)
to be more of a 'usual' approach to an object model. You can see the approach
with mixins in many scripting languages, Rust's entire object model, Haskell's
typeclasses, Elixir and Clojure's protocols, ect. ect.

The fact that you can classify things into a classification tree does not mean
that the classification is how things actually work. If it so happens that
classification trees work for a problem, you can build them with trait
inheritance, but structural inheritance hasn't been that useful IME, so the
marrying of both types with classical inheritance just leaves a bad taste in
my mouth.

~~~
nly
To have 'structs that implement various traits' you must first have structs.
That is, objects with some known immutable shape. Implementing any kind of
trait (interface) to an 'object' having a mutable structure (like the
dictionaries used for modelling objects in most dynamic languages) would be
tricky without exposing some crap to the programmer at the language level. Off
the top of my head you'd need at least something like Perls 'bless'[0] coupled
with Rusts strong protections against mutation.

Whether you choose to define your classes in the form of (possibly
intersecting) sets of objects having some particular trait, or set of traits,
or in some taxonomic tree is fairly irrelevant. The difference is largely a
matter of taste. I think the point Bob (munificent) is making here is that
'scripting languages' (whatever you consider those to be) generally don't give
you anything.

[0]
[http://perldoc.perl.org/functions/bless.html](http://perldoc.perl.org/functions/bless.html)

------
samirmenon
This seems like a wonderful language for game development. I wonder if there
will be some kind of graphics support, or if I can use the C API (when it is
finished).

~~~
munificent
The intent is that you'd use the C API. Or, with luck, someone will make a
little game engine similar to Löve2d that bundles Wren along with a renderer
for you.

------
jafingi
Great work! Love the well-documented source. Will definitely look through it
and try out the language.

I have used Swift quite a lot in 2014, and loved the way to do ranges. But
it's the complete opposite of Wren:

1...8 includes BOTH 1 and 8. Wren would not include 8.

Is this an error in the documentation, or the actual design of the language?

In the beta of Swift, 1..8 was not including 8. But I really like a change in
the final version where it instead is done using 1..<8

It makes it much easier to discern between the two;

1...8 1..8

vs.

1...8 1..<8

~~~
munificent
> Is this an error in the documentation, or the actual design of the language?

It's the actual design. It follows Ruby and (I think?) Perl. Personally "..."
feels more naturally inclusive to me since it has one more "." than ".." and
thus one more item in the result.

But I thought it would be more helpful to follow in the footsteps of existing
languages. The Swift solution is definitely explicit but looks kind of ugly to
my eyes.

Syntax design can be hard.

~~~
gjm11
I wonder about something like

    
    
      for (0 <= i <= 10)
    

which has obvious (and transparent) variants for making one or both bounds
exclusive. For bonus points

    
    
      for (10 >= i >= 1)
    

etc. for looping downwards. You could have unbounded loops too

    
    
      for (0 < i)
    

where you can tell which bit is meant to be declaring a loop variable because
it's always the one after the inequality. For extra points, make
mathematicians happy with things like this:

    
    
      for (0 <= i < j < 10)
    

which does 45 iterations or

    
    
      for (1 <= i,j,k <= n)
    

which does n^3 iterations, where again you can tell which bits are meant to be
declaring loop variables: all but the first and last. These are less
transparent because they don't make it clear what order things should be done
in; they might also introduce the temptation to introduce fancy syntax to
control this, to skip to "the next value of i", etc., which might be
complexity that doesn't pay its way.

This plays pretty well with filtering as in list comprehensions:

    
    
      for (1 < i < j < 100) where (isGood(i) && isBad(j)) { ... }
    

One possibly-killer drawback to this kind of thing: it makes for a nice for-
loop syntax but there's a lot to be said for saying that for-loops are always
just iterating over some sort of collection, and turning these into
collections might again require more syntactic complication than they justify.
E.g., the simplest would be something like this:

    
    
      for (i in (i : 0 <= i <= 10))
    

which feels painfully repetitititititive with all those "i"s and doesn't
generalize well to the fancy versions with multiple variables (but maybe those
are a bad idea anyway). It's not hard to think of ways to reduce the
repetition but they have their own drawbacks and in any case this comment is
too long already.

[EDITED to add: All this only makes sense if your syntax allows for "chained"
inequality operators. But it really should anyway. (It looks like Wren's
doesn't at present, maybe because it's hard to square with the principle that
infix operators are always just single-arg method calls in disguise.)]

~~~
munificent
That starts to look fairly complex to me. In code that I've looked at, doing
numeric iteration is actually not that common. The majority is just iterating
over collections. Wren's grammar for loops is actually really simple. It's
just:

    
    
        for (<variable name> in <expression>) { ... }
    

That's it. Note that there's no special support for numeric ranges. Instead,
".." and "..." are just regular operator calls. The number type implements
them to return a range object. That lets you do:

    
    
        for (n in 1..10) { ... }
    

But also enables:

    
    
        var range = 1..10
        for (n in range) { ... }
    

And even:

    
    
        var items = ["a", "b", "c", "d"]
        var slice = items[1..2]
    

Making the range a first-class object lets you get a lot of mileage out of
using it in different places, which is nice. In fact, a range derives from the
sequence base class, so you can also do:

    
    
        var evens = (1..10).where {|n| n % 2 == 0}

~~~
gjm11
Yup, strongly agree that having a single iterate-over-collection construct and
a nice notation for ranges has big advantages. (I did say that before, but I
guess it was buried in among a lot of other stuff.)

The drawback is that the nice terse range notation leaves it unclear whether
your ranges are inclusive or exclusive (and I conjecture that if you asked 100
experienced software people to guess which of 1..8 and 1...8 is which, you'd
get something close to 50% jumping each way).

What I'd really like is a syntax for ranges that has clarity comparable to
"for (0 <= i < n)" but terseness comparable to "0...n", without being too much
a special case. Unsurprisingly, I've never yet seen one.

Here's a less-than-half-baked proposal, though. Probably too quirky for Wren.

1\. Some syntax like [1 <= i < n] -- inequality operators, delimited in an
appropriate way -- indicates a range object and, at least at parse time,
carries around an indication of the name of the index variable. (Index
_variables_ if we allow fancy stuff like [1 <= i < j < n].)

2\. "for <literal-range>" is syntactic sugar for "for (i in <literal-range>)"
where i is the name of the variable. (If we allow fancy multi-variable ranges,
this only works if your for-loop is able to bind multiple variables as with
"for (i,j) in [(1,2),(3,4)]" in Python.)

3\. Perhaps "for <literal-range> where <condition>" is likewise syntactic
sugar for "for (i in <literal-range>.where(<condition>))" or something.

4\. So far, this is less general than your .. and ... operators because it's
all special-cased for integers. Except there's no reason why it needs to be.
Perhaps, e.g., [a < i < b] invokes a magical method on a, which gets passed
the upper bound b and an indication of direction and inclusivity at each end.
My fancy multi-variable forms can be implemented in terms of this without any
further magic, though not maximally efficiently.

[EDITED to add: It happens that I quite often have use for numeric iteration,
and even for the fancy multi-variable forms I've described here. But I'm
probably atypical.]

------
JadeNB
I know it's not really substantive, but it's tweaking my OCD: why does 'small'
in the list of adjectives in the marketing code block have an embedded
newline?

~~~
munificent
No good reason at all. Removed it.

------
soapdog
Wren appear very cool but I think Finch is more my cup of tea. Anyone has
feedback on Finch or an opinion on Finch vs Wren?

~~~
pierrec
This is from the linked website, in the Q & A page:

 _Wren is a replacement for Finch to me. I gave it a new name mainly so that I
can keep Finch around in case other people want to take it and do something
with it. I don 't have any intention to work on it anymore._

