
Wren is a small, fast, class-based concurrent scripting language - jay_kyburz
https://wren.io/
======
xscott
Wren seems like a really clean alternative to a language like Python, but it
makes one mistake that really drives me nuts. In order to provide binary
operators, you must implement a method on the left object. From the
documentation [0]:

> The left operand is the receiver, and the right operand gets passed to it.
> So a + b is semantically interpreted as “invoke the +(_) method on a,
> passing it b“.

This means that if you want to implement complex numbers, or matrices, or a
bunch of other useful stuff, you'd have to be able to extend the type on the
left (which you didn't write). You really want to be able to do things like:

    
    
        var z = Complex.new(1.0, 2.0)
        var result = 3.0 - z
    
        var A = Matrix.ident(3, 3)
        var scaled = 4.0*A
    

Python hacks around this by having "right' versions of these methods too. It's
kind of ugly - if the left object fails to support the operator method
(__sub__ or __mul__) with the right type, the interpreter looks for a __rsub__
or __rmul__ operator on the right object to try. Ugly, but it works.

C++ works around this a much better way: You can either have the operator
method on the left object, or have an overloaded operator function that isn't
tied to either object.

Rust puts the operators on the left object too, but in some cases you _can_
add methods/trait specializations to left classes. Unfortunately, Rust doesn't
let you do this with generics, but that's a longer more complicated topic.

Maybe there's some way Wren lets you tack on additional methods to the builtin
Num class (monkey patching), but I couldn't find it. I would love an elegant
alternative to Python, but this is enough of an issue that it keeps me from
using Wren.

[0] - [https://wren.io/method-calls.html#operators](https://wren.io/method-
calls.html#operators)

~~~
byroot
You also have the Ruby solution of calling a `coerce` [0] method on the right
hand side.

[0] -
[https://github.com/ruby/ruby/blob/0703e014713ae92f4c8a2b31e3...](https://github.com/ruby/ruby/blob/0703e014713ae92f4c8a2b31e385718dc2452eac/lib/matrix.rb#L1589-L1602)

~~~
xscott
I don't know Ruby very well, and I'm curious how this would work with my
example above. It seems like Ruby's builtin number types, upon not knowing
what to do, calls coerce on the right-side object. That right-side object
returns a pair of new objects, and then the binary operation is called as a
method on the left one of those?

If I've got that right, it sounds functionally similar to the Python way. It's
a little awkward if you want different types depending on the operation. For
instance, maybe A-B returns a different type than A/B. In both subtraction and
division, it looks like Ruby would call coerce(), and coerce doesn't know the
operator. Still that could build some smart placeholder type that _then_ knows
how to treat the operations differently...

For my example with Complex and Matrix types, it seems like the Complex type
would need to implement the coerce protocol on its own. Maybe I've got that
wrong, but does the coerce thing automatically happen for _any_ type, or is
that special behavior implemented by Ruby's Number types?

~~~
byroot
> If I've got that right

You did.

> it sounds functionally similar to the Python way

It definitely is, however it allows to handle all operators by defining a
single method, so it's a bit more usable.

> does the coerce thing automatically happen for any type, or is that special
> behavior implemented by Ruby's Number types?

Only for number types. For other core types using binary operators, you have
dedicated implicit conversion methods. For instance `"foo" \+ MyType.new` will
try to call `MyType.new.to_str`.

`to_str` being specifically for implicit conversions, and `to_s` for explicit
conversions. So implicit conversions won't happen unless specifically defined.

~~~
xscott
This approach seems nice in that it fast-tracks the common case and only
delegates if needed.

> it allows to handle all operators by defining a single method,

That's nice and pragmatic too.

Back to the subject of this submission, I suspect the coerce idea could be
bolted onto Wren without really breaking or changing much of anything (just an
additional branch in the error handling of Wren's builtin Num type). That
would allow Wren to grow it's own numpy-like library someday.

------
dang
If curious see also

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

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

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

------
wcarss
One thing I love about javascript is the ability to quickly and easily
assign/remove whatever fields I'd like:

    
    
        let a = {};
        a.somename = "some val";
        a.newname = "some val";
        a["a computed name"] =  "some other val";
        delete a.somename;
        if (a.neverseenthisbefore) {
          log("just doesn't log!");
        }
    

Python dictionaries requiring the ["fieldname"] syntax or .get to avoid
KeyErrors on undefined keys has always pained me when whipping something short
together. Similarly, here in Wren it seems like Maps require substantial and
strict syntax, and Classes are not meant to allow definition of arbitrary
Fields at runtime.

That one small thing is a key piece of flexibility I want when experimenting.
I shouldn't need to write a getter and a setter down in a distant file on the
correct place in a class hierarchy just because I chose to latch a bit of
temporary state onto an object while I do a bit of work.

In serious code for serious business, that kind of freedom and nonchalance can
be quite dangerous. But when I'm having fun and just trying something, which
is the only context where I'm really trying new languages out for the moment,
the guard rails chafe!

(still, this looks like a pretty neat little language)

~~~
shezi
Side note: You can use python classes for that. It's a common pattern for me
to have something like this in my projects

    
    
        class Holder:
            pass
    

Simply add any attributes at runtime. It's essentially a different interface
for the built-in dict of the instances. Add a bit of getattr magic and you can
read undefined attributes, too.

------
_bxg1
> The VM implementation is under 4,000 semicolons.

> Lightweight fibers are core to the execution model and let you organize your
> program into a flock of communicating coroutines.

> Wren is intended for embedding in applications. It has no dependencies, a
> small standard library, and an easy-to-use C API.

------
wespiser_2018
Wow, this would be ideal for me to write loadtests in! In broad strokes, I
just want to spin up N threads making request after request, in an event loop
with basic tracking. Is there a JSON or Network library available yet?

~~~
jay_kyburz
There is this. [https://github.com/brandly/wren-
json](https://github.com/brandly/wren-json)

------
jermo
Would like to start using Wren though issues like this put me off: "Stack
corruption" [https://github.com/wren-
lang/wren/issues/761](https://github.com/wren-lang/wren/issues/761)

Using older and more established languages seems less risky.

------
darksaints
I believe this language was originally the creation of the guy who wrote the
crafting interpreters book, but it definitely looks like it has grown well
beyond his influence.

~~~
tloru
From what I understand, this language was indeed developed by Bob Nystrom.
AFAICT, He's passed the torch to the team behind the Luxe game engine, which
uses wren as an embedded scripting language for game programming.

------
MR4D
Looks like what JavaScript would be like without all the baggage from the
‘90’s.

------
liigo
I've an issue on Wren's FFI: binding foreign methods is slow.
[https://github.com/wren-lang/wren/issues/648](https://github.com/wren-
lang/wren/issues/648)

------
molsson
The name wren is already used by:
[https://projectwren.com/](https://projectwren.com/)

~~~
eis
The Wren language has been around a lot longer than the project you linked.

------
nerdponx
I'd be interested in if this is comparable to Gleam, a BEAM-based scripting
language, that I discovered through HN.

~~~
dnautics
I believe gleam is a compiled language, and no more of a scripting language
than say erlang (with escript) or elixir (via .exs files).

~~~
nerdponx
I see.

I also realized after I posted that Wren is apparently meant to be embedded.

------
gotzmann
The guy behing Wren is Bob Nystrom, member of Dart language team and author of
Crafting Interpreters book.

------
vaibhavthevedi
Looks nice. It reminds very much of C and C++ programming. What are some of
its use cases?

~~~
dejv
I am building tool for generating PDFs
([https://docula.app](https://docula.app)) and I am using Wren to allow user
scripts: things like show/hide label on some value or maybe display number in
red when the value is > 0 and green otherwise. I was thinking about using Lua,
but Wren seems more approachable to me.

~~~
vaibhavthevedi
I like your product. Do you find Wren reliable when implementing features,
like did it ever broke?

~~~
dejv
Well, it seems to be working very well, but I am still in development mode
with one customer and very little scripting going on. I will know more after
general public is going to use it and will try to use things I haven't think
about.

I am not that concerned of Wren failing as a language, but I looking for a
ways to prevent users write code that doesn't work without having to know what
is going on, which is something Lua is excellent in (typo in variable name in
if statement? Valid code for sure)

------
jbverschoor
Looks like ruby with {}. Performs like ruby

------
hota_mazi
> Wren is fast. A fast single-pass compiler to tight bytecode

Bit of equivocation here.

Wren is dynamically typed. It will never be fast.

At best, it will probably be one tenth as fast as the slowest statically typed
language.

Maybe it's fast to compile, but it will never run fast.

~~~
smlckz
[https://wren.io/performance.html#why-is-wren-
fast](https://wren.io/performance.html#why-is-wren-fast)

------
da39a3ee
> Wren is a scripting language.

As far as I know "scripting language" doesn't have a widely-agreed upon
definition and we should all stop using it.

If anyone were to ask me, I'd say that a "script" is a program that contains a
sequence of commands. It executes transiently for some side effect, as opposed
to creating a persistent process responding to events.

So for example, bash is clearly a scripting language, and if one is being rude
about the appropriate uses for perl, then perl would be too. Python can be use
for "scripting" but certainly isn't in general a scripting language by this
definition. And I don't really think "scripting language" is a helpful term
for Javascript, since it's most important role by far is in as an event-driven
persistent process. However, some people (especially old-school C-programmer
types) use "scripting language" to mean an interpreted language, I think.

I think for Wren, maybe it's referring to a usage of "scripting" that C
programmers associate with Lua?? None of the things it mentions are things
that I personally associate with the word "scripting":

> Wren is intended for embedding in applications. It has no dependencies, a
> small standard library, and an easy-to-use C API. It compiles cleanly as
> C99, C++98 or anything later.

Or is the idea that both Lua (and thus Wren) and Javascript are "scripting"
languages in the sense that they augment an executable written in a "proper"
language with additional run-time functionality? If so, then that's
interesting but I don't think many people get it (it only occurred to me while
writing this) and we should clarify the terminology.

~~~
andrewflnr
I understand about avoiding unclear terms, but I think "scripting language"
actually does serve a useful purpose as an umbrella term for all those kinds
of languages. It's not technically precise, but if you describe a language as
"a scripting language", it does clear away a large part of the design space
(not Haskell, C, Forth, or J) and tells you that this is meant to be user-
friendly as opposed to performant, terse, high-assurance, etc. That's worth
something. Of course if someone is still interested, then you want to get more
precise pretty quickly. I think Wren does well enough at that on its landing
page.

~~~
da39a3ee
> user-friendly as opposed to performant, terse, high-assurance, etc.

Strange, I really don't see that as an axis worth recognizing with that, or
any, terminology (but whenever I bring this up I get voted down, so I guess
more people agree with you.)

I think the core of my disagreement is that, just because a language is user-
friendly, that does not mean that it is not a "professional" or "high-
assurance" language. I'm not saying that you are using it in this fashion, but
I believe that with the terminological strategy you are suggesting, the term
becomes a pejorative, wielded by those who use (C/C++/Rust/Java/Haskell/etc)
as a subtle put-down to people who are using more user-friendly languages.

Related, I think it's a rather confusing axis that doesn't fit the space of
programming languages well:

Go is user-friendly (I gather) and verbose, but performant and high-assurance.

Python is user-friendly and terse, but non-performant and low-assurance (I'm a
python programmer, but the run-time bugs put it in that category if we're
comparing to statically typed languages). A lot of website HTTP handlers are
written in Python, so "scripting" language seems like a very poor description
for what it's doing there.

IMO reasonable axes that are worth recognizing with terminology include
interpreted vs compiled, statically vs dynamically typed, weakly vs strongly
typed, but do not include {user-friendly} vs {performant, terse, high-
assurance}.

~~~
andrewflnr
It might make more sense if you think of "scripting language" as being a
statement of intent than a technical classification. I have seen it used as a
perjorative, which I agree is stupid.

More generally, performance, ease of programming, correctness, etc are goals,
whereas typing systems and compilation strategies are techniques that can be
used to reach those goals. "Axes" is probably overthinking it, as none of
these criteria or properties are linear, but terms for all of them can be
worthwhile if used to answer the right questions.

Since goals have a strong influence on technical properties, it's not
completely crazy to summarize a language's technical features in terms of its
goals. "Scripting language" makes sense as a description for languages that
emphasize ease of programming (with overtones of interacting with a larger
system) over other features. You also have a clue about a language called
"high performance": probably not interpreted or dynamically typed (although
exceptions include kdb, arguably Java and Julia).

Finally, not every term needs a rigorous definition in terms of more primitive
terms. Sometimes you just need a name for a category that everyone kind of
knows is there. This is probably the more realistic origin of the term, though
I do think the underlying reason for that category existing is mostly the
goal-driven one described in my previous paragraph.

Note: In the bit you quoted, I certainly didn't mean to say that "user
friendly" was necessarily opposed to all those other goal properties. I was
just trying to give examples of other things you might want to prioritize in a
design.

