HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
wren-lang
wren
Wren2013–2025
wren-lang / wren

wren

The Wren Programming Language. Wren is a small, fast, class-based concurrent scripting language.

25Distinct people
44Mentions
1Explicit recommenders
8.2KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

The Wren Programming Language. Wren is a small, fast, class-based concurrent scripting language.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

I feel like a good place to share some of the resources I've compiled from HN regarding compilers/interpreters construction: MOOC/Courses: -…

roknovosel used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 10:49:33 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year44 dated mentions

Observed mentions: 2013-12-27 04:52:48 UTC to 2025-10-26 19:50:55 UTC.

024682013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20132014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 5 mentions; 1 submissions, 4 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments20192020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2025

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC101
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC606
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC606
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC808
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC505
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC514
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC404
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC303
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC202
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC211
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC000
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC000
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC211

What Hacker News says

6 sources
> the code is fast (written in C, which _almost_ makes it fast by default). I hate to be that guy, but [Citation Needed]. Most language implementations are written in C and most language implementations are quite slow, once you include the giant slew of hobby, toy, and less successful languages. Remember, Ruby, Python, and early versions of JS interpreters were all written in C too and are or were dog slow! Duktape does have a section on performance[1], but it's basically just a guide to things you have to do to not make it extra slow. I didn't see any reported benchmarks. This doesn't mean Duktape is bad. Simple+slow is a perfectly good trade-off for many real-world uses. Embedded scripting languages tend to spend most of their time in the FFI, not executing code, so perf doesn't matter as much as maintainability. But it's really dubious
Read the rest
to just say, "well, it's written in C so it's probably great." It's using ref-counting and linear scanning or hash table lookup for property look-up. Perf is likely not great. Just as a point of comparison, my little hobby language[2] is also written in very simple C, but it's carefully designed to be fast too. Property look-up and method calls are just pointer + known offset. GC is tracing. Because of this (and other stuff), perf actually is good[3], typically better than Python and Lua and on par with Ruby. (With the usual caveat that all benchmarks are bad. :) ) [1]: http://duktape.org/guide.html#performance [2]: https://github.com/munificent/wren [3]: https://github.com/munificent/wren/blob/master/doc/site/perf...
In Duktape: an embeddable JavaScript engine
> Was very glad to see them come to python and soon to mainstream javascript. I really need to get around to writing a blog post to explain this in detail since this misapprehension is endemic. Python and JavaScript do not have coroutines, they have generators. Lua has actual coroutines. The latter is dramatically more expressive than what you can do with what Python, JavaScript, and C# offer. This mistake drives me crazy because it means people don't know what they're missing. Here's a quick example. Let's say we've got a little Python class for binary trees: class Tree: def __init__(self, left, data, right): self.left = left self.data = data self.right = right We'll add a method to do an in-order traversal. It takes a callback and invokes the callback for every data value in the tree, like so: def
Read the rest
walk(self, callback): """Traverse the tree in order, invoking `callback` on each node.""" if self.left: self.left.walk(callback) callback(self.data) if self.right: self.right.walk(callback) We can create a little tree and then print the data items in order like so: tree = Tree(Tree(Tree(None, 1, None), 2, Tree(None, 3, None)), 4, None) tree.walk(print) (This works in Python 3, in Python 2, you'll have to make a little fn for print.) Swell, right? Later, we decide we want to iterate over the items in a tree. Easy-peasy, Python has generators! We can just make a function that takes a Tree and returns a generator. We already have a method to walk the nodes, so we just need to call that and then yield the items, like so: def iterateTree(tree): def callback(data): yield data tree.walk(callback) Then you can just use it like so: for x in iterateTree(tree): print(x) Perfect, right? Actually, no. This doesn't work at all. You can't yield from the callback passed to walk. That's because walk() itself doesn't know that the callback is a generator. This is the problem with generators: they divide all functions into two categories: regular functions and generators. You run a regular function by calling it. You run a generator by iterating over it. The caller must use it in the correct way. At its simplest level it means you have to be careful when refactoring. If you have a generator function that gets too big and you want to split it up, you have to remember that the functions you split out are also special generator functions if they contain a yield. You have to remember to flatten it when you "invoke it". It's more than just annoying though: it means it's impossible to write code that works generically with both kinds of functions. In other words, all of your higher-order functions like map, filter, etc. now only work with some of your functions. (Or, I suppose, you could explicitly implement them to support both but that's more work and I don't think most languages do.) In languages like Lua, the above code just works. You can yield from anywhere in the callstack and the entire stack is suspended. It's fantastic. (If I can be forgiven a bit of self-promotion, I'll note that my programming language Wren[1] can not only express full coroutines like Lua, but also supports symmetric coroutines which can express some things Lua cannot. They are roughly like the equivalent of tail call elimination for coroutines.) [1]: https://github.com/munificent/wren
In Why C++ for Unreal 4
What I find interesting here is that Python (and most other dynamically-typed languages) treat instances of classes as arbitrary bags of properties, with the negative performance implications of that, even though that feature is rarely used. I'd love to have the time to examine codebases and get real data, but my strong hunch is that in Python and Ruby, most of the time every instance of a class has the exact same set of fields and methods. These languages pay a large performance penalty for all field accesses, to enable a rare use case. JavaScript VMs (and maybe Ruby >=1.9?) don't pay the perf cost because they do very advanced optimizations ("hidden classes" in V8 et. al.) to handle this. But then they pay the cost of the complexity of implementing that optimization. I'm working on a little dynamically-typed scripting language[1] and on
Read the rest
e design decision I made was to make the set of fields in an object statically-determinable. Like Ruby, it uses a distinct syntax for fields, so we can tell just by parsing the full set a class uses. My implementation is less than 5k lines of not-very-advanced C code, and it runs the DeltaBlue[2] benchmark about three times faster than CPython. People think you need static types for efficiency, but I've found you can get quite far just having static shape. You can still be fully dynamically-dispatched and dynamically type your variables, but locking down the fields and methods of an object simplifies a lot of things. You lose some metaprogramming flexibility, but I'm interesting in seeing how much of a trade-off that really is in practice. [1] https://github.com/munificent/wren [2] https://github.com/munificent/wren/blob/master/benchmark/del...
In Why Python Runs Slow, Part 1: Data Structures
Running LuaJIT interpreted is a deliberate choice. Some platforms, in particular iOS and game consoles, do not allow generated machine code. I want my language to be usable for games, and that's one reason I'm using bytecode. (Simplicity is the main reason.) Given that, I think it's most helpful for me to compare Wren's performance to other bytecode language implementations. Comparing to JIT compiled languages is a bit apples/oranges. They tend to be something like an order of magnitude faster (and an order of magnitude more complex!). Meanwhile, LuaJIT's interpreted mode is very fast as you note. I think it's one of the fastest bytecode interpreters around, so it's a great target for Wren to aim for. If you want a lot more detail on my thoughts about this, see here: https://github.com/munificent/wren/blob/master/doc/site/perf...
In Ruby 2.1: Out-of-Band GC
Anecdote time! I've been hacking on a little scripting language[1] lately. To see how its performance compares, I run a few benchmarks[2] against other similar (dynamically typed, bytecode compiled) languages: Lua, LuaJIT (interpreted), Python, and Ruby. Like others, I had internalized "Ruby is slow" through osmosis. But the version of Ruby I happen to have on my machine is 2.0.0. In my little benchmarks, it turns out Ruby is one of the fastest. I haven't compared to 1.8.7, but I'm guessing that was much slower. [1] https://github.com/munificent/wren [2] https://github.com/munificent/wren/tree/master/benchmark If you want the gory details, here's the results of running them against Lua 5.3.2, LuaJIT 2.0.2, Python 2.7.5, and Ruby. (Yes, I should try against Python 3. I will.): score time wren score relative
Read the rest
binary_trees - wren 3193 0.31s binary_trees - lua 1366 0.73s 233.72% binary_trees - luajit 6256 0.16s 51.04% binary_trees - python 1376 0.73s 231.96% binary_trees - ruby 3003 0.33s 106.34% fib - wren 3078 0.32s fib - lua 2785 0.36s 110.52% fib - luajit 6900 0.14s 44.62% fib - python 1331 0.75s 231.37% fib - ruby 3548 0.28s 86.77% for - wren 6080 0.16s for - lua 1990 0.08s 50.71% for - luajit 5914 0.02s 13.24% for - python 2825 0.35s 215.25% for - ruby 6595 0.15s 92.19% method_call - wren 4707 0.21s method_call - lua 1674 0.60s 281.17% method_call - luajit 4221 0.24s 111.53% method_call - python 767 1.30s 613.69% method_call - ruby 3061 0.33s 153.77% As you can see, Ruby fares quite well.
In Ruby 2.1: Out-of-Band GC

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.