Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Pony is an open-source, actor-model, high performance programming language (ponylang.org)
95 points by kordless on Jan 14, 2016 | hide | past | favorite | 57 comments


The audience of a programming language are developers. Developers like code, code speaks to us. Actual code samples are a few clicks away: http://tutorial.ponylang.org/getting-started/helloworld/

pony-lang devs: put some examples on the home page!


While they're at it, they should also add the following list from the "Static vs dynamic" section of the manual to the web front-page, as a sort of crie de coeur.

    If your program compiles, it won't crash.
    There will never be an unhandled exception.
    There's no such thing as null, so your program will never try to dereference null.
    There will never be a data race.
    Your program will never deadlock.
    Your code will always be capabilities-secure.
    All message passing is causal.


Came here just to say this! Please add code snippets on the home page. Here are a few things that I'd like to get an idea about from the language's homepage - Concurrency, Type safety, Pattern Matching and Higher order functions.

Visually examining a code-snippet that directly communicates the above would be a huge sell!

A few examples to look at

1. Rust - https://www.rust-lang.org/

2. Elixir - http://elixir-lang.org/

3. Go - https://golang.org/



Still don't understand those capability types (iso, trn, ...). Need more tutorials!


this is what I was looking for, thank you :) I should have kept scrolling clear to the bottom of the nav, I gave up early.


Strongly agree. The main webpage for any programming language should always include a bit of sample code -- generally a short but nontrivial complete program.


completely agree, syntax does matter but your link doesnt show much syntax better look here http://tutorial.ponylang.org/expressions/methods/


Were you able to find more information about the runtime? I'm curious about things like message queueing and ordering guarantees.


The papers[1] is where is the meat is.

> Ownership and Reference Counting [...] We propose Pony-ORCA, a fully concurrent protocol for garbage collection in the actor paradigm

> with shared memory [...] introduces a new form of write uniqueness

> a dedicated actor for the detection of (cyclic) garbage

So, Erlang + shared state? Rust + GC + green threads?

I'm very happy there is activity in this space; I feel like there a whole class of massively online realtime applications just waiting to happen.

5k users first person shooter anyone?

[1] https://github.com/ponylang/ponylang.github.io/tree/master/p...


  > Rust + GC + green threads?
I haven't used Pony much yet, but when I first saw it, this was my first connection. In some, but not all, ways, it is like what Rust used to be at a certain moment in its history. The languages have different goals, so it's not like I think this means Rust is better or something.


No, I don't think the similarity is big. Pony is all the way about asynchronous/nonblocking messaging. Rust with green threads was favoring synchronous/blocking calls, just like Go, which probably also suits the ownership model better.

So Pony might be better compared to Erlang with a strong type system and without a blocking receive method than to Rust or Go.


Yeah, I mean, this is why comparing languages solely based on feature lists is a bad idea; it's also about things like idioms. It's more like, "in some ways, Rust was trying to be similar to Erlang, and in some ways, Pony is trying to be similar to Erlang, so in some ways, Pony and Rust are kinda similar." Emphasis on the 'kinda'.

(And I'm thinking about Rust _pre_ ownership model, here. And Rust does have non-blocking IO, just not in the standard library. It's not imcompatible with ownership.)


    wget -O - http://releases.ponylang.org/buildbot@lists.ponylang.org.gpg.key | sudo apt-key add -
This is not secure. Non https connections cannot be trusted. It is trivial for a cafe owner to MITM this and now he is generally trusted with your apt-get. BAD.


This looks interesting.

There are a few things I wonder about. From the first page of the tutorial (http://tutorial.ponylang.org/):

> It's exception safe. There are no runtime exceptions. All exceptions have defined semantics, and they are always handled.

This seems contradictory. Are there exceptions or not? EDIT. Apparently there are (http://tutorial.ponylang.org/expressions/exceptions/). But then I don't understand what the above means.

> It's deadlock free. This one is easy, because Pony has no locks at all!

This is nonsense. Deadlock happens when multiple processes/threads are waiting for each other. It is not caused by locks.

From another tutorial page (http://tutorial.ponylang.org/types/static-vs-dynamic/):

> There's no such thing as null, so your program will never try to dereference null.

But there is "None" (http://tutorial.ponylang.org/types/primitives/). How is "None" so different from this "null" that we want to avoid?

On the positive side:

As I said this looks interesting. The type system appears to have been well thought out. Intersections look like a sane way to provide functionality that other PLs either implement poorly (perhaps via "multiple inheritance"), or simply disallow.

And if the type system really does offer all the claimed guarantees, then it is a very good thing indeed.

The partial applications, the concurrency model, and the handling of immutability are also clearly features that someone has given a lot of thought to. I cannot judge the results at this point, but I like well-thought-out things. :-) And the notion of "apply", along with the shortcut syntax, seems like it provides a standard, easy to understand way to make lot of code pretty simple.

I hope to be able to look into this PL more closely in the near future.


> > It's exception safe. There are no runtime exceptions. All exceptions have defined semantics, and they are always handled.

> This seems contradictory. Are there exceptions or not? EDIT. Apparently there are (http://tutorial.ponylang.org/expressions/exceptions/). But then I don't understand what the above means.

I think the author is using a terminological Java-ism. In Java, a "runtime exception" (RuntimeException and subclasses) is an exception that doesn't have to be handled, and therefore may be thrown unhandled at runtime. Pony has exceptions, but no unhandled exceptions, i.e. no "runtime exceptions" in Java speak.


Yes, that's probably what is meant.

So the point is that a program will never crash due to an exception.


>> It's deadlock free. This one is easy, because Pony has no locks at all!

> This is nonsense. Deadlock happens when multiple processes/threads are waiting for each other. It is not caused by locks.

Actually deadlocks happen when 2+ resources are not locked in the same order by 2+ processes/threads... As far as I know, in Pony there's no way to send a blocking message to another actor, so there's no lock, so there's no deadlock.

Please correct me if I'm wrong


I shall refer to a higher authority:

> A set of processes is deadlocked if each process in the set is waiting for an event that only another process in the set can cause.

That is from Modern Operating Systems, 4th ed. (2015), by A.S. Tanenbaum & H. Bos, page 439. (By "process" they really mean "process or thread".)

One way for thread A to wait on thread B is as you said: thread A can request a lock that thread B currently owns; then A waits for B. So requesting locks in opposite orders can result in deadlock. But of course if there are no locks, then no such waiting occurs, and so deadlock from this cause is impossible.

But there are other ways to wait. If var_a and var_b are shared variables, then code like the following might result in deadlock (The following code is in C; to simplify things, I'm assuming that data races and memory-access ordering are not issues.)

Thread A does:

    var_a = 1;
    while (var_b != 0) ;
    var_a = 0;
And thread B does:

    var_b = 1;
    while (var_a != 0) ;
    var_b = 0;
If Pony is capable of executing code like the above, then deadlock is possible.


Pony prevents you from writing that code. All communication between actors is by message passing, and there are no global variables. Check out reference capabilities.


You can deadlock in purely message passing code, even if there are no blocking sends. See an example in Erlang: http://james-iry.blogspot.com/2009/04/erlang-style-actors-ar...


That anti-pattern isn't possible in Pony, because Pony has no blocking receive call.


Of course, and Pony prevents programmer from writing code that waits for anything else. Sure. We're supposed to believe this?


Wow, so maybe the no-deadlock guarantee really does say something nontrivial. Thanks for the heads up.


There are many ways code can grind and thrash to a halt, like your code shows. But a deadlock refers specifically to the idea of two processes waiting until the other is done before they proceed. It's a scheduling problem, and a lock is used for synchronization. If there are no locks (spinlocks, semaphores, etc), there are no deadlocks by name (just other problems).


> ... there are no deadlocks by name (just other problems).

Okay, supposing we have a definition of deadlock that agrees with your usage: sure. But then these "other problems" you mention will have exactly the same practical effect as deadlock, right? A program will hang, sometimes unpredictably, based on more or less random decisions made by some low-level scheduling algorithm.

And in that case, Pony's guarantee of no deadlock is (1) completely correct, and (2) completely meaningless, from the point of view of a programmer whose concern is that his code will behave as required.

Am I wrong? EDIT. Maybe: https://news.ycombinator.com/item?id=10903876


  > How is `None` so different from this "null" that we want to avoid?
The difference is the defaults. Languages "with null" generally assume that any value can be null. Other languages, like Pony, do not allow any type to be null.

Pony's "None" type is an example of a "unit type": a type with only one possible value. It's a totally different thing.


Ah, I guess I misunderstood. From the tutorial:

> Pony often uses the primitive None to indicate that something has "no value".

So that is not a special value that we can assign to any variable.

"None" would seem to be pretty pointless all by itself, but I guess we could do a union of any old type with "None", to get a result much like Haskell's "Maybe". And then the Pony type system would give us much the same guarantees as Haskell's would; so we get a nullable variable that still allows for typesafe operations -- e.g., dereferencing, if applicable. (I guess ....)


Yeah, when I read the parent comment, I thought that None was part of a type like Maybe, but the next sentence describes it as a unit type:

  > Of course, it does have a value, so that you can check what it is, and the value is the single instance of None.


Yes, but, as I noted, Pony has type unions (http://tutorial.ponylang.org/types/type-expressions/). So you can roll your own Maybe types.

From the page I linked above:

> var x: (String | None)

> Here we have an example of using a union to express an optional type, where x might be a String, but it also might be None.

That's pretty clearly a Maybe.


Maybe (at least in Haskell/Rust) is a sum type, not a union type, though.

EDIT: Ugh, sorry, those are the same, I was thinking of sum vs _product_ type, ignore me.


Is a union type (at least in Haskell/Rust) structured like a union in C, where alternative types of values (e..g. int, float, char) occupy the same bytes, just not at the same time? Or is separate space allocated for the different types of values? Asking because, if a function returns a union type, with one type within it representing an integer (which can have any value), and if the function also wants to return an error condition, then no valid integer value can be used to indicate the error, because all integer values are valid return values from the function. In this case I would think that a union type should have separate space allocated for the integer value and the error-signalling value. (Something like what golang does with its return values?)


There are two major forms of sum type implementations that I'm aware of: tagged and untagged. What you're describing is a tagged union, for exactly the reason you state: there's an extra field for a discriminant which lets you choose the tag. Untagged unions are C's unions, where there's no discriminant, and you just have to know which type is valid at a given time.

Rust supports tagged unions, but can also optimize them to untagged in certain circumstances. We will probably add some kind of untagged union as well, mostly for FFI, but they're very unsafe, for the above reasons.


Got it, thanks. Interesting about Rust's design goals and tradeoffs.


Similarly, Pony's union (ie sum) type implementation always optimises to untagged, but required "boxing" raw machine-words when they're in a union type.


Actually, I think you've noted a significant issue: Pony looks to have been designed, at least in part, based on a sound theoretical foundation provided by modern type theory, semantics, etc. However, the documentation does not use the standard terminology of these fields. As a result, it is difficult to evaluate some of the claims that are made.


The Haskell void type () is also a None, and it's pretty helpful. The easiest example is `putStrLn :: String -> IO ()`.


you may be safe from "dereferencing null", but you'll still have to check for those edge cases, whether it's called Null or None


No, because random values cannot be None. The only thing that can be None is something with the type "None".


I see many examples where they do exactly what I described, checking for "None" as a parameter value. Sure, it's explicitly named as a possible value, but you STILL have to make the check yourself.

http://tutorial.ponylang.org/pattern-matching/match/#matchin...

I see how it can be used in new and different ways, and is definitely safer, but it's not like the idea of "that thing you want isn't here" goes away by introducing a None type.


I think I prefer the Option type to using a union with None here, for the reason that you state. I'm coming at this from a type theory / language design perspective: unit types are very different than nullable types, though if you write a union type with unit as one of the possibilities, well...

EDIT: Sorry, I was thinking of sum vs product here, union types are sum types. So this is the same thing as Option. Sounds good. The advantage of using a union type is that you _have_ to check. This is significantly better than nulls.


They're both sums, but Pony (and e.g. Typed Racket) has unlabelled unions, while Haskell/ML have labelled unions. Pony's (X | None) is not like Haskell's Maybe X in that in Haskell, X could be unit, while in Pony that would collapse the type to just None. In other words, in Haskell, Maybe (Maybe X) makes sense; in Pony and Typed Racket, it doesn't.


Yet another terminology issue: do you mean tagged vs untagged? IE, there's an extra field for the discriminant. Or rather, Pony does _not_ have a discriminant, but Haskell/ML do?

(I am 99% sure that's what you mean, but since I already screwed up terms once in this thread...)


That's roughly it. I was referring to a difference at the type system level, rather than the runtime level, though.

Disjoint unions aka sum types (as seen in Haskell/ML etc) entail some runtime way of keeping track which side of the sum any given inhabitant lies on. Tags are one way to do this, but e.g. in a language where pointers/references are never the zero machine word, and unit is represented as the zero word, no tag would be needed for the type Maybe String.

Union types (as seen in Pony, apparently, and also in Typed Racket), by contrast, /don't/ preserve information about which side of the union an inhabitant came from.

So, disjoint types: A + A ≠ A but union types: A ∪ A = A

So expanding (Maybe X) into (X + 1), we have that (Maybe (Maybe X)) = ((X + 1) + 1) ≠ X + 1,

but if instead (Maybe X) expands to (X ∪ 1), we have that (Maybe (Maybe X)) = ((X ∪ 1) ∪ 1) = X ∪ 1 = (Maybe X).

This is one of the problems with uses of null in languages that have it.


I found the statement regarding runtime exceptions confusing as well. Perhaps what is meant by that statement is that Pony lacks unchecked (i.e. Java) rather than runtime exceptions.


Yes, that's probably it.

Or to put it more simply: an exception will never crash a program.


Whence the high performance claim? I tried finding some benchmarks, and apparently they used to be on the home page since this was on HN about a year ago, but I didn't find any recent ones. It would be nice to see it compared to, say, Rust, Nim, Haskell, OCaml, C...


That's a good point.

But I do see where the claim is coming from. Pony is aimed at the same kind of compile-to-bare-metal that we do with C, C++, Fortran, etc. Furthermore, Pony's design explicitly deals with many of the issues that get in the way of aggressive optimization in other PLs: pointer aliasing, dynamic type checking, data races, etc.

So Pony was clearly designed with high performance in mind. And it seems likely to me that the efforts made in that direction are practical, workable ones.

But that is not the same as saying, "We can write a Pony compiler that generates fast code." And it is certainly not the same as, "We have written a Pony compiler that generates fast code."


Looks like they use LLVM backend, so they'll get low level optimisation for "free". The GC is also interesting: fully concurrent and lock-free.


Well, it's faster than C++ with OpenMP so it's definitely the fastest safe language around. For sure faster and safer than Rust, and it looks better to the eye also. What I'm missing are FFI finalizers and GC triggers as with libsigsegv. Long running hungry actors can force unhandled out of memory.


The grandparent was looking for concrete evidence/examples for the "high performance" label, not just another assertion of high performance.



There's some benchmarking of simple fib type things here [1].

[1] https://cdn.rawgit.com/darach/my_little_pony/master/my-littl...


I find this interesting, but a bit too complex.

As a hardcore JavaScript programmer I make use of clusters or spawn child process to handle "actors" and I think that is much easier to reason about.

I would be happy if Pony had some examples of how to manage "world" state. For example if two objects in a 2D world intersects, or when one actor fires a laser, decide if another actor was hit by it.

I'm writing server code for MMO's and it seems like Erlang, Pony, etc would be the magic tool for such systems, but I never seem to "get it".


Erlang is far from "a bit too complex": it's just not.

What is difficult from devs coming from the imperative world is getting recursion & bind-variables-only-once (what is commonly known as "the syntax is ugly").

Please, have a look at http://learnyousomeerlang.com/content


I think it is fair to say that developers don't have most sensibility when it comes to UX, and often UI, so I think let's allow Pony Lang maintainers to make site a little bit easier to read and attract us.

Honestly, these days, we have a lot of choices, you really need to woo us, show us why would we want to program in this language.


Definitely seems more practical than the other pony language, FIM++




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

Search: