Hacker News new | past | comments | ask | show | jobs | submit login
The Lobster Programming Language (strlen.com)
387 points by openbasic on Apr 3, 2019 | hide | past | web | favorite | 164 comments

Hi, author of the language here.

Not a great time for HN exposure, as I just added a lot of new functionality, but none of that is documented yet :) But hey, all publicity is good publicity?

For those interested, some recent things that have been happening:

- Compile time reference counting. This does an analysis similar to the Rust borrow checker to infer lifetimes, but unlike Rust doesn't make the programmer jump through hoops.

- "Inline" structs: structs are allocated in their parent, and come at zero overhead compared to individual variables, which is particularly useful for Lobster's heavy use of 2d & 3d vector types.

- Multi-threading that uses separate memory spaces, meaning individual threads can run at max speed with no GIL overhead etc.

- A WebAssembly backend is being worked on.

- A lot of optimization work to make the language run faster.

For reference, it has been on HN before, as early as 2013 (https://news.ycombinator.com/item?id=5904430), but it has changed a TON since then (e.g. it was a dynamically typed language, now it is statically typed, with flow sensitive type inference).

Hi! I might be an embarrassingly gushing fanboy about everything you do, so I'm probably biased here. (I wrote the FlatBuffers Wikipedia page, for example.) Lobster is pretty inspiring (despite not being nearly as radical as, e.g., Aardappel) with its lightweight lambdas and (like most of your work) a very minimal core language.

Is there a comparison of different versions of Lobster somewhere? I'd like to be able to make statements like "My new language XYZ, unlike Lobster, is dynamically typed, resulting in difficulties such as plicplocpluc in developing the IDE" but different versions of Lobster now cover such a large part of the language design space that this is becoming difficult. For example, that statement doesn't make sense with respect to old versions of Lobster, which were also dynamically typed.

Hah! Thanks a lot for the wikipedia article :)

Yes, Lobster is meant to be a much more pragmatic language, for people like myself to actually get the job of making a game done :) Other languages of mine are much more research-y. Though I will say I think the type system and lifetime analysis are pretty novel actually.

I'd like to think there's really only one Lobster, while older versions are still recoverable, they for practical purposes don't exist anymore :) Have you seen https://htmlpreview.github.io/?https://raw.githubusercontent... ? That actually contains some history.

Holy cow, are you the Quake Aardappel? That is a name I haven't heard in a long, long time...

Yup, the one and only :) Do I know you as well?

Nah, just a forum lurker who had a folder full of mods and maps and engine binaries much too large much too late.

Didn't know how to code back then, and probably can't rocket jump anymore now. Mostly just surprised at having that old memory surface out of nowhere.

Thanks for making that scene cooler way back when.

Let me take the opportunity to thank Wouter for the wonderful Amiga-E language I had the pleasure to use a long long long long time ago in a very different galaxy. Thanks!

Where's my "like" button.

Hah, thanks!

You should check out Sauerbraten.

Would you mind elaborating on the "compile time reference counting"? Is this new? How does it handle cycles?

It is so new I haven't even documented it yet.. hence why I said the timing for this HN post isn't great.

So imagine the current implementation does a lifetime analysis somewhat similar to Rust, but then where Rust would error out, this implementation simply inserts a runtime refc increase. This gets rid of most runtime refc overhead without the programmer needing to be clever about it.

Then, I intend to add an optional type annotation that gets you the Rust behavior, for those cases where you want maximum control. I don't think its the right default though.

The algorithm is more lenient than Rust, since I don't have any shared memory concurrency for example.

I intend to write up more thorough details about the algorithm, but again, haven't gotten to it.

It does not handle cycles. If you create cycles that you do not manually break, you'll get a cycle report at program exit that prints the kind of values that weren't reclaimed. You're then expected to fix your code accordingly :)

This at first glance actually looks similar to http://liu.diva-portal.org/smash/get/diva2:20899/FULLTEXT01....

And this style of static analysis has been taken even further by Luc Blaeser: http://concurrency.ch/Content/publications/Blaeser_Component...

The cycle checker I'll have to have a look at - I'd like to crib parts of it for an OS I'm trying to cobble together. Your project looks very interesting, thanks!

Thanks for those, I hadn't seen them. The Ritzau paper indeed appears to be doing something very similar, where in 5.2 he describes "inner references" whose lifetime is bounded by the outer one, I call that "borrowing", where the outer definition (the owner) gets locked from mutation during the borrow.

What I do is a bit more involved though, as for every language construct I indicate if it wants to own or borrow its children (and wether it wants the parent to own or borrow), to remove maximum refcounts, also for cases which are not simply variables. Again, I will describe this in detail.

The second paper I don't see how it relates to what I am doing.

That sounds more similar to Swift's approach, where the compiler does aggressive optimisation to elide reference counts were possible. Do you agree?

Yes, it is more similar to Swift than Rust. I guess people are more familiar with Rust.. since Swift hasn't actually implemented it yet?


The compiler has implemented a lot of the infrastructure for reasoning about ownership, and has had optimisation for eliding reference counting operations for a long time (but the ownership stuff makes them simpler).

> I don't think its the right default though.

I think Rust should allow this kind of relaxed ownership, with ARC behind the scenes, as lots of user level code should not require fussing over ownership details. A "get shit done" mode.

Rust supports proc macros, you know-- you can do literally anything with your code. So what you describe is already possible! Make a good proof of concept and submit a proper RFC for it, and it might even be adopted as part of Stable Rust!

Yes, that is exactly my intention, for the majority of code this compile time reference counting is good enough.

You can of course use Rc types in Rust, but that is verbose, and throws all ownership out the window, unlike Lobster.

Any chance you could you share some references on this kind of type inference? It sounds very interesting!

It is not an implementation of an existing paper or anything.. I am going to write it up soon, promise!

Feel free to email or msg me if you want to be notified.

More on the compile time reference counting here: http://aardappel.github.io/lobster/memory_management.html

A comparison to Swift's ARC would also be of interest :)

Yup, I will write up the algorithm some time soon.

I've seen Swift's intentions to add lifetime analysis to ARC, but from what I could see it is much more complicated in Swift, requires annotations, and with significant runtime overhead remaining.

Arc isn’t that stuff, Arc is what it already does today. “Automatic reference counting.”

I'm aware of that, I said "add lifetime analysis to ARC", as in, ARC is what I call regular runtime reference counting, and with lifetime analysis some of it can move to compile time.

Yep oops, sorry.

Anyway, psyched to see more people experimenting with this kind of thing!

Yes, I frankly feel this design space is the future of memory management. GC, begone!


This seems to scale out very well - it's kind of static GC analysis with RAII and erlang-style messaging.

Weird, just yesterday, there was a link from a different language that seemed very similar to yours or at least has similar goals: http://cone.jondgoodwin.com/

Not sure if I'd call these similar, Cone looks more low level, with more explicit typing etc. Looks cool though.

Are the coroutines copyable? This is useful if you want to use time-travel netcode (like ggpo) and coroutines attached to game objects in the same game.

I'm afraid they currently aren't, but there's no reason this couldn't be implemented. There's a "copy" function for reference types that currently errors on co-routines.

That sounds great :)

I found it a bit strange that the coroutines run until the first yield at the time they are created, but otherwise I quite like the system.

Do you plan to accommodate multi-line lambda? Python is hamstrung on this front thanks to the white-space oriented formatting.

> Python is hamstrung on this front thanks to the white-space oriented formatting.

You could have multiline lambdas with Python's signficant whitespace, the then-BDFL just didn't think it was important enough to accept any of the syntax options proposed for it or to bother finding another option, believing named functions were sufficient for the multiline case.

It already does multi-line lambdas (lambdas and built-in control structures share the same syntax), see e.g. the call to "fold" here: https://htmlpreview.github.io/?https://raw.githubusercontent...

f# has white-space oriented formatting.

OCaml doesn't care about white space, and I don't think SML does either, although F# does. Maybe you are thinking of Haskell?

i am sorry. you are right. i misremembered about sml (haven't written in it much and in a while) and incorrectly lumped in ocaml. i should have been more careful. f# was what was really on my mind.

  - Multi-threading that uses separate memory spaces, meaning individual threads can run at max speed with no GIL overhead etc.
Hmm? Does that mean that they are actual processes sharing no memory? EDIT: If so then that's a big downside. In Rust you get thread-safety for traditional, shared-memory threading/concurrency. Ideally you should be able to get as good as Rust for threading. Ultimately, I think it all depends on this:

  - Compile time reference counting. This does an analysis similar to the Rust borrow checker to infer lifetimes, but unlike Rust doesn't make the programmer jump through hoops.
I mean, that would be a huge win, but there must be a trade-off. Can you elaborate?

This does not mean separate processes, it simply spawns one "VM" per thread. Lobster VMs are pretty light weight (just a self contained object that has everything for a program to run). The advantage is that everything inside one VM can be single threaded, down to memory allocator. The threads then communicate by sending each other lobster values, similar to a "tuple space". I personally think this explicit communication style of concurrency is safer and easier to use than shared memory concurrency.

As for the lifetime analysis, see some sibling comments: I need to do a good write-up of the algorithm. I wasn't anticipating this HN post :)

Ah, OK, sure. And I assume that Lobster compiles to bytecode then, that gets interpreted?

Even if it does mean separate OS processes (which I doubt), keep in mind that on Linux basic POSIX threads are basically just processes with some shared memory mapped in. There's no real performance difference.

It looks nice! Do you have a gallery of games made with Lobster available somewhere?

There's a lot of great technical info on the homepage, but it's tough for me to see the forest for the trees here. Could you make a short (probably oversimplified; that's ok) case for what Lobster is especially good at and why it's worth using rather than other programming languages? Or direct me to where one is already written?

At a glance, one thing that makes it stand out is that it's minimal like a framework, but allows you to code in something with similarities to python, but with more design towards that task. Most python-esque languages are poorly suited for games in terms of performance/features.

Seems to nail most of the desires of mobile/indie scale development.

I was hoping the current homepage had that function, with a list of special features followed by some examples.

You want it shorter? Something like "Get Python-like ease of use together with static typing and speed and built-in game programming functionality" ? That really doesn't do it justice. In the end, like most languages, it is a particular cocktail of trade-offs, and to see whether this suits you, you need see the full list of features.

Maybe you want a list of features with an example for each? It's hard to make it short though, especially the type system.

Not features. Benefits.

Benefits show an increase in something good or a decrease in something bad.

Better speed. Less code. Easier distribution. Lower cost.

A lot of the benefits are hard to express in numbers, and I am not a marketing person.

Does this particular kind of type system help you in your software engineering? Very hard to quantify, and depends on circumstances and even personal preference.

I don't think I have any hard-number benefits that are meaningful.

Heyy @Aardappel Interesting project!

I wanted to share your language with a game programmer I know but the links to documentation from your homepage look broken.

Essentially https://htmlpreview.github.io/ is dysfunctional. Try accessing the sample links in that project's Github page.

Weird, those links work fine for me.

I guess I'll have to change them, though not sure what to.. annoying github doesn't have a way to view markdown pages.

I guess for now, to read the docs online you could read the raw markdown here: https://github.com/aardappel/lobster/tree/master/lobster/doc... Better yet, just download the repo and read the html files in docs/

Now all docs served from http://aardappel.github.io/lobster/lobster/docs/README_FIRST... which works much better

Looks really interesting. Have you done any write ups on the type inference bits?

Flow sensitive type inference looks like exactly what I need.

There's an informal description here: https://htmlpreview.github.io/?https://raw.githubusercontent...

But yes, I should really write up a more technical description some day.

The standard work on flow-sensitive higher-order type inference proceeds from Olin Shivers's dissertation, but Oortmerssen has written a bit about his ideas on lambda-the-ultimate.

Do you have any plans to support building statically linked binaries like Go?

Currently the only way to do that is via output to C++. This will give you static binaries, but it is of course a more complex build than Go's direct executable output. Not sure if I'll ever do native codegen myself (as in, direct x86 or ARM), currently working on WebAssembly support, and LLVM IR is also a possibility.

Pretty cool.

How does it compare to Dyon?


Hadn't seen this, thanks! At first glance, it appears that the difference is that Dyon is dynamically typed and requires the programmer to get lifetimes right manually (though annotations, ordering, or clone), whereas Lobster is statically typed and does all lifetime analysis automatically (and falls back to a runtime reference count increase when analysis fails). You'll be able to force the Rust/Dyon behavior manually with a type annotation in the future.

> all publicity is good publicity

... unless it's an obituary :)

(an old joke)

Btw, you have a bunch of dead links to Google+ (readme, the linked page, etc).

On http://strlen.com/lobster/ I only see a dead link to Google+ (which I'll remove, thanks!), but no other dead links?

Sorry, I meant you link to google+ a bunch, not you link to many different dead things.

That I've noticed: Twice on that page, once in the readme, again in dev/readme and lobster/readme.

A very cool domain name, by the way.

Is there a list somewhere of games written in Lobster?

No, most of them are unreleased. Here's one though: https://store.steampowered.com/app/687560/Avoid_The_Monsters...

can you drop the need for the : at the end of the line if there's a newline? i.e. it seems like unnecessary syntax

That would make it much harder to parse in certain cases, both for the compiler and the human, given that it uses this same syntax to parse not just control structures, but also higher order functions / lambdas.

I like how ruby does it


Why would you think that? As an industry we’ve been moving more toward automatic formatting, enforced formatting via lint, and a move toward more standardization with white space. What would be the reason to not have it required by the language itself?

Because it is a sufficiently divisive decision that it limits the audience. The threshold before I'd consider working with a language with significant indentation for example, is huge. And for my part at least, I've yet to see an automatic formatting tool that formats how I find things most readable.

>Because it is a sufficiently divisive decision that it limits the audience.

Considering Python is the 2nd or 3rd top popular language in indexes like TIOBE and job entries, and within the top-5 for over a decade, that's empirically false.

It might put off some insignificant minority (that's superficial like that), but not enough people not to be hugely successful.

Given I personally is unwilling to use Python for that reason, and know other people as well, it is empirically true. We can argue over whether the number of us that refuse to use it is big enough to matter, but for my part I have no interest in the pain of dealing with that, and I have the freedom to choose it away.

Some things can be popular despite their shortcomings.

Which is neither here nor there, as the accusation I was responding to was that "it limits the audience".

Other languages can only dream to have such "limited audience" as to be ton the top-3 TIOBE...

Yes, it is directly relevant. And sure, many languages can dream of that level of use, but most other languages do not have the luxury of being there, and then making decisions that demonstrably do keep some people from using even a language as widely used as Python is worth at least thinking about. Especially when category of languages that does this is already dominated so thoroughly by Python.

Do you actually have any data on how many people don't use Python because of significant whitespace? I suspect it's actually a very vocal minority -- it's about as well-formed of a reason as refusing to use C++ because it requires semicolons.

It's a matter of personal taste, so it does not need to be "well formed". These things are more religious questions than about rational arguments. As for numbers, no, I don't. All I have to go by is the number of people I know or have met that dislike it. And so I know it is polarizing, but beyond that it is guesswork. The point was not to claim that it is some massive proportion of developers, but to point out that decisions of taste are not inconsequential.

On first look, the language seems superficially similar to Nim. Which, per se, is certainly a plus in my book! ...but makes it somewhat difficult to understand when should I pick one or the other. Could you point out some important differentiators? (Apart from the current set of available libraries, which certainly make it appear more useful for the intended target audience at this very moment AFAIU, but in longer perspective are potentially somewhat secondary.)

It does have some similarities, mostly in the sense that both are using a Python-esque syntax, but that doesn't mean they have similar semantics.

Some difference off the top of my head:

- Nim so far has been a GC-ed language (I know manual allocation is possible, and an ownership system is planned, but this was the default for most code so far). Lobster has been reference counted (and now compile time reference counted) from the start. Nims proposed ownership system is pretty cool, but still requires a fair bit of programmer cooperation, in that sense it will sit somewhere between Rust and Lobster in terms of programmer friendlyness.

- Lobster has a type inference algorithm that is able to go further than most languages in terms of allowing code without types to "just work". Nim has nothing even remotely like this.

- Nim is faster. Nim was designed for near native speeds from the start, Lobster started life a very high level language that slowly become more low level. There's nothing that prevents Lobster being as fast as Nim, it just will take a bit more time.

- Nim is more mature, in the sense that it has been around longer, has more libraries and tooling etc, and a larger community.

- Lobster has great support for programming with higher order functions: terse syntax, best possible type inference, zero overhead (compared to manual loops), non-local returns etc.

So in summary I'd choose Lobster over Nim if you care about Lobsters type and memory management or higher order function features, or if you like the idea of a language that makes games/graphics out of the box easier. If you just want to "get the job done", Nim probably is ahead of Lobster at the moment :)

Lightweight syntax and zero overhead for higher order functions sound fantastic. I'm very interested.

I have never understood why people create entire programming language when just creating a nice C++ library would been more than sufficient, desirable, integratable and adaptable. You can always export bindings for any target language and users would be saved from learning yet another beast that would be unmaintained in few years. I'm not saying never developing new language... If you have radically new thought, go ahead do it but just keep combining feature1 from this language and feature2 from that language doesn't make a lot of sense (especially the part of taking completely unrelated unsearchable word to name your language).

C++ is a complex beast and while I quite like working in it, I'm finding that the latest versions (17 and 20) are filled with features that I'm having trouble understanding. The surface for errors is also huge. I've been programming in C++ since about 2002 and I feel quite proficient in it, but, if given the option, I'll use something that is both safer/less error prone and more productive (and I say that as someone whose argued right here that C++11 and beyond is a very productive language).

Beyond that and what sibling comment said, the author is known for creating various languages, so he clearly enjoys doing it and is making this language for himself.

I have never understood why there's always somebody complaining that new languages are unnecessary when a new language is shown on HN. I personally love seeing new languages. I also recently went on a language hunt for something that met a specific need for a side project I'm working on and I came away empty handed because I couldn't find something that met my criteria[1], so I'm always on the lookout for something that might.

[1] In case somebody has any suggestions for me, I want something with Clojure-like immutable data structures as a default (or something similar, at least), is native compiled to reasonably efficient and low footprint binaries (but is not as complex as Rust or Haskell), is a functional language (but with prettier syntax than OCaml, which was almost my choice, but when I started reading example code, its a complex mess of symbols <insert perl joke>). And... it needs reasonable library support... (at a minimum I need to be able to respond to HTTP requests, make HTTP requests, parse and generate JSON and talk to postgres, ideally using SQL and not an ORM). Haskell is probably my best bet, but I don't have the energy to learn all of its complex features.

I'm not against creating new languages. In fact the Lobster language is something I would want (although current syntax is bit repulsive). Python with static types but without getting in the way is pure gold. The problem is that creating interpreter/compiler is one tiny little part of creating language. Much bigger task is creating vast number of libraries that every other popular languages have. Think about everything from numpy to scipy to graphics to networking to web frameworks to OS APIs... Another bigger part is creating tooling and interoperatibility - everything from debugger, refactoring, linting, IDEs, CI, docgen etc. Now put on the top of it all the reusable code that millions of people have already written spending billions of hours in existing languages.

Without large teams working for years, its very hard for a new languages to break in to general use. There are ofcourse outliers and you can get lucky - but then you have to be terribly lucky. So the end result is that 99.9% of languages just die or become hobby project for a person regardless of their features, benefits, beauty or aesthetics. Again, nothing wrong with becoming personal hobby project but if my goal was to create game engines that becomes force in the industry, I would probably not start by creating entirely new language.

I'm not experienced as much as the author, so this is my personal opinion and likely not very well informed. I writing this just because I see several people spending years in creating new languages while their goals have been something else. They dream about repeating success of Java while not realizing how rare it is. After they finish their labor of love, I wonder if they find it depressing to become just line item in the list of dead programming languages. What if they would have actually focused on their original goal instead with emphasis on adding new powerful features that integrates and plays well with existing stuff? It's sure not as sexy and respectable as being father (or mother) of new language but has much higher chance of generating desired impact.

You are not wrong. But you are assuming every language author must be wanting to become the next mainstream language. I am already aware Lobster will unlikely be that, and I am fine with it. I am having a ton of fun developing it, and I have used it for many projects. I do not want to have more impact by working on something more boring :)

Because the language affects how you think about things, and how productive you are. It matters.

And in this case, this is someone with a 20+ year background of experimenting with new languages, ranging from production-ready (e.g. I used AmigaE a lot back in the 90's) to crazily experimental ones.

C++ is a deeply, deeply flawed programming language carrying decades of baggage to stay backwards compatible. Let's not pretend that mere inertia is enough reason to keep using the same tools forever.

Major reason why many game engines used to have native core and then some kind of "scripting" language for game logic (think Unreal Engine before 3, but many engines are similar) is that then you can trivially serialize the simulation state (ie. save game) and even run the whole thing as either lock-step, forward predicted or fully distributed network game without much effort on the part of whoever is writing the "scripting language" part of the game code.

Agreed, those are nice benefits. But there are also huge downsides, in the sense that you're writing all the glue code in the wrong language :) The amount of speed of iteration you get from having your entire engine + game's structure in a friendlier language is impressive (in my experience).

Also doing savegames by just serializing the entire scripting VM may work in some cases, but can also be problematic, since you're mixing ephemeral data with gameplay state. Last U3 engine game I worked on had explicit savegame serialization :)

My point is that having scripting VM that is explicitly designed for game logic allows you to serialize only the relevant state. And if the whole system is designed correctly you can also do checkpointing and streaming replication essentially of the game state for free. This buys you things like rendering thread that is decoupled from the simulation (just draw the snapshot of state that was current on the start of rendering iteration), non-synchronized joins of multiplayer players (send serialized checkpoint and do stream the changes until the client catches up) and so on.

I agree, for that level of integration you want a "gameplay scripting system", whereas Lobster is more of a general purpose programming language that happens to be a nice starting point for simple games & engines. I don't think in its current form it is a great language for a large AAA team anyway, because of its heavy reliance on type inference and lack of separate compilation.

The language could of course be adopted to these use cases, it simply hasn't, so far.

Doing simulation on a separate thread from main/rendering is something it is already set up to do (multi-threading uses separate memory spaces so it is easy to ensure there's no data races between the two).

Also, you can never update your data structures without ruining all of your safrgames.

Good point. I actually made this with game serialization needs in mind originally: https://google.github.io/flatbuffers/

I use Haxe which is a

Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.

what would be the benefit for using Lobster since I can work directly with each OS with a great scripting language built in?


Haxe can translate to an impressive set of languages and platforms, so if that is your main need, I'd say, stay with Haxe.

Haxe and Lobster are very different programming languages however, so you may prefer one over the other purely for the language design.

If you like portability, Lobster already runs on 3 desktop OSes, 2 mobile ones, and the web, using either VM, C++ or soon WebAssembly modes. While not as extensive as Haxe it is pretty good :)

I'd like to know this as well.

Did you create a VM that is several times faster than Python's, for a static typed language thats as productive as a dynamic language, with true multithreading? How did you outdo entire language communities?

Python's default implementation is so incredibly slow, such that any programmer that implements a new language that doesn't just make "everything dynamic" will automatically end up with a language that is faster than Python without really trying.

There are probably a 1000+ language implementations out there that are faster than Python, most of which are single person efforts.

Lobster is a much more static language, and does inlining of functions, inlining of structs, specialization etc that allow it to remove a lot of runtime cost, such that even the VM is fast.

It also has been in development for about 8 years now. I've been working on compilers in one way or another for almost 30 years.

I'm a huge proponent of typed languages, but there's no way that a statically typed language could be as productive as Python (with current type systems technology). For example, just the Pandas library offers incredible flexibility (often dynamically based on the arguments that different functions get) that I've yet to see replicated in a static language.

My experience is that you start out very productive not being weighed down by having to satisfy the type checker... but programs tend to grow over time and you end up regretting it. When you have a medium to large codebase in a dynamically typed language it gets to be more of a hindrance than a help.

I agree, but my point was rather that you can't typecheck Pandas (or a similarly complex library). Gradual typing for the win!

That's a very low bar. It's just that Python programmers don't care about any of this. The productivity is already enough for them.

I don't really see the point in using Python syntax and then throwing in a handful of random differences that don't have anything to do with the domain you're working in. Syntax level support for vector operations or for shader interopability I would get. Making for loops follow some randomly different syntax, I don't see the point of that.

It is not intended to be Python compatible, it merely has indentation based syntax that is similar.

The cases where it differs from Python are actually for good reason: unlike Python that only has built-in control structures, here any function can look like if/for/while if it takes a lambda body.

This seems like a cool way to make an ad hoc dsl. I'm not a game programmer but I imagine it could be useful.

This seems like a cool way to make an ad hoc dsl. I'm not a game programmer but I imagine it could be useful

Smalltalker here. Being able to pass in lambdas very casually is a great way of producing an ad hoc DSL. Imagine a custom control structure which does a database transaction. Just implement a function!

Yup, this style of programming I use all the time in Lobster.

> unlike Python that only has built-in control structures, here any function can look like if/for/while if it takes a lambda body

That's absolutely fantastic. I've had to do a lot more Python programming for work, and I've been thoroughly disappointed by Python's lack of support for custom blocks/structures like that (contrast with Ruby or Elixir, where any function can take a do ... end, or with Tcl where "blocks" are just strings).

So is it a bit like Rebol (or Red, or even Joy if we pretend RPL is not a significant difference), or is it a very different style of implementation?

I welcome languages that take the idea of indentation as part of the language. I don't see that as belonging to Python, and I don't believe this language aims to be Python-compatible as opposed to inspired.

> I don't really see the point in using Python syntax and then throwing in a handful of random differences that don't have anything to do with the domain you're working in

I don't think it's using Python syntax, I think it and Python share some similarities. Thinking about it in Python terms is probably why the changes appear random/different/useless. But in general not being constrained by Python or another language has value.

Also 'include'? Why would you add the single most awful part of C/C++ to a python-alike.

It's not supposed to be a python-alike. It just happens to use indentation for blocks.

#include causes the preprocessor to replace it with the specified file. Why is that bad?

Because ostensibly we've moved on from that to the concept of actual modules.

'including' stuff entails a whole host of ugly things including multiple definitions, circular dependencies etc. etc..

Most languages use some kind of module resolution, which when specified clearly is usually better. Of course sometimes they forget to define things, and leave us in a lurch ... but hey ...

You're reading too much into the keyword.. in Lobster, this does never include anything twice. Circular dependencies just work, without having to pre-declare anything. I should probably rename it.

I suggest people might pick up on that pretty quick, maybe no need to rename given some random comment. That said, maybe you want to have a gander through the various languages and see what words are used for what, and if there's a 'standard' go with that :)

Cool language though. I love everything except for the name, sorry :)

Well, every time Lobster surfaces somewhere, I am always surprised how quickly people can superficially reject it because of some syntax issue, so yes, I agree, using predictable keywords where it makes no real difference matters. I've already made quite a few such changes.

The name.. I think people will quickly forget about the original meaning. Think of all the languages you know, and how you associate the name with the language, not some snake, a musical note, degraded iron, a french philosopher, etc. Some of these names are actually pretty silly.

The fact that you keep encountering it suggests that it's probably something in human nature to associate words, that ultimately don't matter, with how we've encountered them in languages in the past.

As for associating the name of the language, the only one I can't get past on that is 'Pony', it just has too much MLP fandom association for me to take it seriously.

Because they got third degree burns by the harmless word. Adolf used to be one of the most common German names, obviously now it isn't. [0]

[0] https://www.beliebte-vornamen.de/wp-content/uploads/adolf-1....

Maybe it's not as superficial, but I tend to ignore all new languages that has significant whitespace. It takes a bit of effort to learn a new language, there are lots of other languages, and I might as well learn a new language that has things I like in it.

> a french philosopher

If Sartre isn't already an esolang built around the concept that hell is other programmers, then someone should make it.

Agree on names, but to be fair, an absurdist comedy troupe is meant to be silly. Speech defect, coffee, an ordinal number. I still feel rust is a bad name.

Of course you're right. But 'Oort' or 'Ort' would be a good names as well.

I thought Lobster was a play on Rust's crab?

This reminds me of processing. https://processing.org/


This looks really fun: https://github.com/aardappel/lobster/blob/master/lobster/sam...

Are the generators implemented entirely in user space using continuation passing style? And the coroutine function turns it into something pausable?

Edit: I can't wrap my head around how return returns out of all the generators

So the non-coroutine case of that code are all regular functions, without using CPS or anything. The only special feature Lobster has is that when you write "return" it will return out of the lexically enclosing named function, not the function whose body it sits in (which can be an anonymous function). This mean return is implemented by unwinding stack frames until it gets to the named function, almost like a lightweight version of exception handling. It also can't resume these functions, like you typically can in languages that support CPS.

Now the co-routine functionality takes an existing higher order function, and compiles it such that the call to the function argument instead does a yield. These are really regular co-routines that are implemented by copying stack frames off and onto the stack upon yield and resume. I just thought being able to share code between HOFs and co-routines was cute, since they often express the same patterns. Why would you write an iteration twice?

I am an old Amiga user Vic-20, A1000, A500, etc., so I am a fan of the author.

I tried running the sierpinski example with a pre-compiled Windows .exe that I placed in the lobster root directory, and it gives me this error: "can't open file: stdtype.lobster".

I placed lobster and lobster/modules in my path, and it still throws the same error. I am assuming I need to build the .exe myself due to some incompatibility with the master branch and this older .exe?

I like a self-contained game PL. I use Raylib for that type of experience right now, but I like the concepts here. Thanks!

EDIT: copied modules to root of lobster, and now I get:

"stdtype.lobster(8): error: end of file expected, found: <"

I tried an included test file and a copy/paste of the sierpinski example, and both throw this error.

Sorry, I need to do better at "getting started" documentation. The exe needs to be placed in the "lobster" dir under the root. It searches for "includes" relative to itself.

Not sure about the error involving "<".. are the executable and the data from the same version of Lobster? Open an issue on github or email me for more help :)

I'll build it as the site suggests, since I am using a binary from the release with the master branch modules. I'll follow up on github. Thanks!

Is the first example's last line:

  var i = find [ 1, 2, 3 ]: _ > r
the same as?:

  var i = find ([ 1, 2, 3 ]) a: a > r
i.e. argument parantheses are optional for one argument; and _ is an implicit argument for a block.

Would multiple functions arguments be done just with parentheses, like this?:

  var i = find [ 1, 2, 3 ] (: _ > r), (: _ < r)
Seems like the syntactic generality of lisp or haskell, with the predictability of performance of C. EDIT I see it's as fast as non-JIT Lua... are there any features that prevent it from theoretically approaching the speed of C?

PS: small detail, but that's got to be the best for-loop I've ever seen.

Yes, those are equivalent.

Multiple function arguments require a keyword in the caller, much like "else" introduces the second function argument in an if-then-else. So if "find" would take two functions, one for even and one for odd list elements, it would look like: "var i = find_even_odd [ 1, 2, 3 ]: _ > r odd: _ > r"

There are no features that prevent it from "approaching" C's speed, merely a question of implementation work. The language started out as very high level, so code generation needs to be improved to not do as many things at runtime as it currently does. The language semantics are totally able to be within 1.5x of C.

Fantastic, thanks.

The many uses of : syntax are intriguing - lambdas, functions, control, python-style structure, data, globals. I reckon you've established it works in all cases, but I'm not yet familiar enough to see that for myself.

For initial adoption, I wonder if more regular sample code, without the special-case abbreviations, might be more effective? (Followed by the short version.) OTOH, maybe at this early stage it's best to select for developers interested/capable enough to handle it!

EDIT if : is used for both blocks and code structure, could everything be one-line (or is \n significant?) Not great style, but helps in understanding the syntax. Maybe returns and vars need their own lines?

  def find(xs, fun): for(xs) x, i: if fun(x): return i return -1

  var r = 2 var i = find [ 1, 2, 3 ]: _ > r

Yes, ":" appears a bit overloaded, though many of those cases are actually one and the same.

What would be more regular sample code? Do you mean just writing "find([ 1, 2, 3 ]) x: x > r" with explicit () and explicit variables? I agree that is easier to read, though the extreme terseness is also a feature..

Yes, everything can be one line, but in this case it would look a bit ugly:

def find(xs, fun): (for(xs) x, i: if fun(x): return i); return -1

> Do you mean just writing "find([ 1, 2, 3 ]) x: x > r" with explicit () and explicit variables? I agree that is easier to read, though the extreme terseness is also a feature..

Yes, amd yes it depends on the purpose. For learning, it can be impossible to parse; redundancy helps distinguish parts and provides a check you got it right.

OTOH for showcasing features, IMHO, the generality of : is a more impressive feature to demo.

Anyway, it's certainly intriguing! And maybe that's the true purpose of showcase code...

Very personal opinion and matter of taste: Many lambda syntaxes are a bit weird.

    map(my_array)element:element*2 //lobster
    my_array.map{|element|element*2} //ruby
    Arrays.stream(my_array).map(element -> element*2).collect(something list something)  //java?
Lobster feels a bit unbalanced. Ruby has "pipes" which are a bit confusing substitute parentheses. Java has the cool arrow syntax but otherwise it feels very glued on. (edited and fixed, thanks for the comment)

Your Lobster version has a stray comma, it is: map(my_array) element: element * 2

Note how if you write this example with multiple statements instead of "elements * 2", suddenly the Lobster syntax looks a lot more consistent, and the Ruby example doesn't look that great as it looks completely different from the built-in for loop.

No-one uses the built-in for loop in Ruby though. Instead, everyone uses the each method which looks the same as map.

That said, the Ruby syntax can be a bit bulky. Your syntax feels pretty clean TBH.

Really stupid question here, but how do I start compiling Lobster programs on my machine (Windows or Linux)?

There are some releases which come with pre-built exes for e.g Windows: https://github.com/aardappel/lobster/releases

I'd highly recommend you build it yourself though, which can be done rather easily with VS (2019) on Windows or CMake on Linux. On Windows just press build in release mode and you're done. More notes here: https://htmlpreview.github.io/?https://raw.githubusercontent...

Then cd lobster && lobster samples/pythtree.lobster for example should run something. Or see here how to use from command line or from your fav editor: http://htmlpreview.github.io/?https://github.com/aardappel/l...


This reminds me of the language used in Godot Engine, maybe talk to them and use this in the engine?

Hah, that would be a pretty good fit, yes.

I really like the inclusion of basic graphics routines. Not a lot of languages include these out of the box and it's something I've really missed since I first started toying with programming in QBasic.

It's kind of surprising to me that the language is directly tied into OpenGL given that it's a cutting-edge experimental new language and that seems more the domain of Vulkan.

It's not tied to, it is implemented in it. I could swap out the rendering code for Vulkan, an no Lobster users would need to change anything.

Also, have you actually programmed in Vulkan? Even a simple primitive can be hundreds of lines of setup code. In Lobster they're often a single line. A direct mapping would not make sense.

000000128039 000000128034 000000128039 000000128034 000000128034 000000128034 000000128039 000000128008 000000128039 000000128008 000000128013 000000128039 000000128013 000000128034 000000128039 000000128034

I enjoyed playing Cube based games, editing maps live and whatnot. Will check this out too!

Thanks, let me know what you think :)

Oh this looks rather nice. I'll have to take a look at this.

Why choosing 'value' as a keyword for types? Super odd

I've actually since changed that to be more conventional. Now the "inline" by-value objects are called "structs" and the regular by reference objects are called "classes" much like C#

> Discuss things in the google+ community


Yeah, cool Google+ community.

Portable python for games...? Does it compile and run natively?

It's not Python.. it just has a similar syntax.

You currently run it either as a bytecode VM (which is rather fast and runs on any platform), or you can translate it to C++ if you want an additional speed boost.

The site says it compiles to bytecode and C++ source. Looking at recent commits, there's some non-functional WASM support: https://github.com/aardappel/lobster/commit/5b89bacd1b1d1e63...

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact