Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Pony: Combining safe memory sharing with Erlang-like actors (ponylang.org)
202 points by samuell on July 2, 2017 | hide | past | favorite | 62 comments


Pony core team member here.

We love when folks notice us, hopefully a couple people who read this end up in the Pony community. That said, the "better-than-Rust" makes me uncomfortable. Pony and Rust have different goals and make different tradeoffs with regard to memory safety. We don't think one is better than the other. They are different.

Anyway, back to my Sunday. Y'all enjoy.


I just had a thought that made me ridiculously excited. Like in Pony, doing FFI in Rust is unsafe for obvious reasons. But would it be possible to define a subset of the typesystems of both languages to have a possibility of calling Rust code safely from Pony? (I doubt it would work another way around, since Pony needs its runtime.) That would create super cool synergy with ergonomic and ultra safe Pony and ultra performant and safe Rust.


I suppose it would be possible although I'm not sure it would be worth the effort. Only one way to find out though.


I think that would be really great. You can already call Rust code via FFI, but it looks like that languages have a lot in common with the LLVM backend, and memory- and type-safety. Imagine the boost to productivity Pony users would get if they could call Rust code from the crates.io ecosystem from Pony, with next to no glue code?


Ok we (belatedly) took "better-than-Rust" out of the title.


Pony core team member here.

Given this is a link to part of the tutorial. I'll drop some additional links if you are interested in learning more:

high-level overview of Pony's value proposition: https://www.ponylang.org/discover/

our current "start here" resources for learning pony: https://www.ponylang.org/learn/

collection of blog posts, videos and what not: https://www.ponylang.org/community/planet-pony/

main compiler GitHub repo: https://github.com/ponylang/ponyc

user mailing list you can sign up for to get more info: https://pony.groups.io/g/user

#ponylang on freenode for IRC (generally very quiet on weekends)


By the way, I run the https://reddit.com/r/ponylang subreddit. I mentioned it a long time ago on the mailing list trying to get someone from the Pony team to join as a moderator, but don't think it ever fully panned out. If anyone on the team is interested, feel free to PM me on Reddit.


What about (multiparty) session types? Can they be implemented for the actors to force them to follow a protocol?


A Gentle Introduction to Multiparty Asynchronous Session Types [1]

[1] http://www.di.unito.it/~dezani/papers/cdpy15.pdf


Is there any web/network framework for Pony?


web framework? no. hopefully someone steps forward to do that. a couple folks have mentioned that they are building one or want to but so far nothing has materialized. personally i'm hoping that someone does a version of webmachine for Pony.

there's a http server that is part of the standard library but it wasn't written to be high-performance. it has good latency characteristics but poor throughput characteristics.

i've written a number of http servers during my career, don't really have the stomach to do another. hopefully in the not so distant future, someone writes one in Pony with an eye towards performance.


Rust is designed to be a systems programming language in that it does not ship with a garbage collector. Pony does have a garbage collector. Comparing their memory safety is comparing very different categories of languages.

It would be better to compare pony's memory safety to a GC language: go, Java, C#, Haskell, etc.


I didn't read the docs in depth, but it seems that the extra safety Pony adds over Go, Java and C# is null-dereference safety, data race safety, exception safety and deadlock safety.

Go, Java and C# all suffer from all the problem above. Go in particular (due to confusing slicing semantics and dearth of immutable data structures) and C# slightly less (due to a lot of syntactic sugar to help you with null-safety).

Haskell is a slightly different beast. I assume that with idiomatic Haskell, except for an occasional runtime error due to bad program logic, you'll rarely run into these issues.


In what category would you put Oberon, Modula-3, Sing#, System C#?


The first three surely in the "nobody uses and don't see that changing anytime soon" category (haven't heard of the last one, special systems-programming C# edition?)


The C# dialect used in Midori.

As for the rest, IT world is full of political murders of nice technology.

As Alan Kay puts it, pop culture driven development.


I agree that it's tragic how little alternative systems are known now. That said, linguistically, sub-structural languages (which can avoid GC) are quite different, regardless of intended usescases.


Please tell me that the referenced C# dialect used in Midori is available in some form for use, research or general learning? This would really make my week!!


Just scattered information.

You have Joe Duffy's blog entries about Midori and one entry back when it was still called M#.

Then there are the little pieces that came to C# from it.

Namely async/await, TPL, the MDIL compiler on Windows 8.x, the .NET Native compiler for UWP, the improved GC control in .NET 4.6 and the planned features for C# 7.1, 7.2 and 8.0 related to more mechanical sympathy.


Edit isn't allowed any longer, so here are some extra informations.

Joe Duffy's blog about Midori

http://joeduffyblog.com/2015/11/03/blogging-about-midori/

Joe's blog entry about what was known as M# at the time

http://joeduffyblog.com/2013/12/27/csharp-for-systems-progra...

Joe's presentation at QCon 2015, "Safe Systems Programming in C# and .NET"

https://www.infoq.com/presentations/csharp-systems-programmi...

Channel 9 presentations about MDIL compiler for Windows 8.x

https://channel9.msdn.com/Events/Build/2012/3-005

https://channel9.msdn.com/Shows/Going+Deep/Mani-Ramaswamy-an...

Channel 9 presentations about .NET Native

https://channel9.msdn.com/Shows/Going+Deep/Inside-NET-Native

https://channel9.msdn.com/events/dotnetConf/2014/-NET-Native...

GC Improvements on .NET 4.6, including memory guarantees for performance critical sections

https://docs.microsoft.com/en-us/dotnet/api/system.gc.trysta...

https://blogs.msdn.microsoft.com/alphageek/2017/01/24/signif...

C# roadmap for 7.1, 7.2 and 8.0 with more memory friendly features

https://github.com/dotnet/roslyn/blob/master/docs/Language%2...

Joe is presenting a keynote at Rustconf, about memory safe systems programming.

http://rustconf.com/program.html#joe


I think that Adrian Colyer's coverage of one of the Pony papers is the best overview of the Pony capability system.

I've found that the capability system is both the most exciting part of Pony and the most difficult part to grok for a new comer.

https://blog.acolyer.org/2016/02/17/deny-capabilities/


You aren't alone. Reference capabilities are the hardest thing for most folks to get a handle on, particularly as they relate to generics.

We have a section of the website on learning Pony that focuses on a "plan of action" for learning reference capabilities:

https://www.ponylang.org/learn/#reference-capabilities


Those were 3 intense days for Adrian, he published two other related articles: https://blog.acolyer.org/2016/02/16/capability-myths-demolis... https://blog.acolyer.org/2016/02/18/ownership-and-reference-...

Both very interesting to read!


Interesting. Looking forward to more comments on this.

* It looks like exceptions carry no error information. When something goes wrong, you know nothing. Is that right?

* Calling finalizers from GC is usually troublesome. They get called late, so they can't be relied to close files and such. They also have to be prevented from making trouble by doing things you can't do during GC, or "re-animating" the object being deleted. How's that handled?

* The notion that variable type is established at initialization is becoming mainstream. How about extending that to structures? The fields of structures could get their types inferred from the structure constructor. (There was a statically typed variant of Python, Shed Skin, which did this.)


> * It looks like exceptions carry no error information. When something goes wrong, you know nothing. Is that right?

Yes and no. You know something went wrong. `error` is supposed to only be used when it indicates a specific thing that went wrong. If you need error information, you should use a union type ala Rust.

There's been discussion on the Pony core team to change the name from "exception" has that carries a lot of expectations these days (folks generally expect that they will be akin to exceptions in Java et al)


God damn there's some good ideas here.

pony: class Foo[A: Any val] c#: public class MyGenericArray<T> rust: fn foo<T>(T) { ... } golang: none, because existing examples (outside of pony) too complicated

Which most obviously suggests a generic func? Geez, took us this long to just reach some clarity? Nice job, Pony.

More: 1 + 2 * 3 // wont compile 1 + (2 * 3) // will compile

yes! I have devs with college degrees who don't understand operator precedence.

Liking what I see so far. Nice mix of low cognitive load/high expressiveness/safety. Keep at it.


> yes! I have devs with college degrees who don't understand operator precedence.

Bitwise operators in C-like languages have precedences that make no sense at all; I can't remember those either. (Even though they sort-of make sense if you consider their historical heritage... no excuses though.) But do you really see software developers with a university degree that mess up the precedence of times and plus? I shudder when thinking about them working with my code. I would really appreciate to be able to write e.g.

    a + b == 0 || c * d - e > f / g
without a misunderstanding of precedence. Why is that not a basic feature in the first programming course one gets? It certainly was in mine, two years ago.

EDIT: is there any way to sanely embed an asterisk in normal text here?


I think the Rust example isn't quite fair, as the Pony and Java examples you give are for types, not functions. The Rust equivalent would be `struct Foo<T>`, which I think is as clear as the Pony example.


The web site promises a proof for type safety and links to a paper https://www.ponylang.org/media/papers/fast-cheap.pdf but the way I understand the paper it doesn't provide a proof. It contains a type system but no proofs of its properties. What am I missing here?



It doesn't contain a proof for the type system either.


Glad to see this on HN. Just a couple weeks ago I stumbled onto Pony. Seems wonderful. Currently I am studying Erlang and Haskell with the hopes of combining the two. Pony seems to achieve a similar aim on it's own. I like that.


Pony actors are not really Erlang-like. In Erlang the scheduler is able to switch between processes at any point during execution (preemptive scheduler) and is also able to garbage collect unused memory in the process at any point during execution.

In Pony developers must write behaviours in a way that allows the scheduler to give CPU to other behaviours and to run GC periodically to collect unused memory. Otherwise other behaviours won't be able to run or will consume too much memory.

https://tutorial.ponylang.org/gotchas/

Erlang processes are also much smarter. They can be linked to each other to be notified when their linked counterparts die. This allows to create a well structured hierarchy of processes, each one with a different role to fulfil in the application.

http://erlang.org/doc/design_principles/des_princ.html

A completely separate issue is their different approach to handling errors. Pony, similarly to Rust, tries to prevent the developer from crashing the application. Usually they do a decent job, but situation where the actor will need to crash or will never return are inevitable (see gotchas above, also imagine some dodgy code executed through FFI, etc).

Erlang takes a "let it crash" approach to managing those situations. Its BEAM (runtime, or VM in which the processes run) is the core that executes all processes. The core is not supposed to crash under normal circumstances but the processes are expected to crash as soon as they can't recover from an error.

http://lists.ponylang.org/pipermail/ponydev/2016-February/00...


How does fault tolerance compare to Erlang? This was what made Erlang so great IMO


Pony looks amazing. This is the first time I've heard of it, but I'm really excited to dive in. I'm only half way through the tutorial and there's already a lot to love. It feels like a cross between Python, Erlang, Rust and Haskell, with a dash of Go. The result is a surprisingly well thought-out language.


I like that env is passed in so that stdout isn't a global.


+1 rust needs more reference types and now I have more ammo to say why.

-2 alias types and especially ephemeral types. Anonymity should be no big deal (e.g. lambda is boring, closing over variables is interested). This seems like a monkey patch over not respecting that principle.


I'll keep on writing Rust and Haskell until I learn more about why I should love the actor model, but I hope this could someday kill Erlang and Elixer.

Good job for being much more interesting than your average new PL post.


Why would you want this to kill Erlang and Elixir? Bad experiences?


Not to get into religious wars, but Erlang and Elixir generally also rock. Caveats: documentation, error messages and REPL could be better.

Pony looks interesting and I hope it develops further.


This language looks wholely better and more unique (or at least once all the beam awesomeness is rewritten could be that), so those others retroactively become watered down versions that add nothing to the diversity of programming languages.

Never been personally bit by those two.


What kind of runtime requirements does it have?


Seems to be garbage collected and the async behaviors dispatched into a threadpool, but no pre-emption.


As far as I remember it is not only no pre-emption, but also no garbage collection inside a single actor method invocation. Which has some advantages but also the downside that longer-running and allocation-rich operations might need to be split up into multiple async actions.

But maybe that model changed in the meantime.


At this time, that is still the case.


That's a reasonable overview. There's work on pre-emption although not everyone thinks cooperative multitasking is a bad thing so pre-emption might be a choice you make on application startup.


It's compiled. No interpreter or VM. Just an executable


Being compiled doesn't means lack of runtime.

C's runtime is called Crt0 in most POSIX systems.


You should not have been downvoted the way you have. Your statements are factual, just seems others think you meant there is no runtime or stdlib. But for runtime requirements, not carrying extra files or requiring extra installs is important, thanks for the info.


I agree ;)

But truth to be told, it was a quick reply without much thought.

Thanks.


"better-than-Rust safe memory sharing" lol it's just garbage collection


You really should do your homework better. Garbage collection says nothing about data races. Also, because of the compile-time memory safety inherent in the type system, they can build a much better garbage collector than whatever you are probably thinking of.

http://www.doc.ic.ac.uk/~scd/icooolps15_GC.pdf


From the naive clueless knowledge of GC implementation algorithms, yes.

From the point of view of those that understand GC implementation algorithms, it is an actor local GC only executed at specific defined points, coupled with capabilities.

Rust use of affine types for memory management is great, but not all applications need such tight memory management, so it is a good productivity improvement to just be able to use a GC approach.


A GC doesn't make data sharing in multithreaded applications safe.


Once you have "Erlang-like actors", you don't have data sharing.


You do in Pony. One point of the type system is to allow safe passing of data between actors without copying everything.


Then you don't have "Erlang-like actors", which is an implementation of CSP (unintended, designed separately, but still).

Unless you mean that some data is shared, but cannot be modified, but this would be semantically identical to not sharing anything.


Shared immutable data is one option, but what I also mean is that when the type system can guarantee at compile time that the actor sending the data does not have read- or write- access to the data after sending, the system knows it can just "recycle" the old data, without run-time overhead.

Look, just read up on the type system, specifically reference capabilities[0]. It's basically what allows for safe mutability and data passing when required.

[0] https://tutorial.ponylang.org/capabilities/reference-capabil...


>Unless you mean that some data is shared, but cannot be modified, but this would be semantically identical to not sharing anything.

That's the gist of Rust's borrow checker. Shared data can't be modified (unless you use a Mutex or something similar, but then you need to acquire a lock, so data you can mutate is not shared).


Erlang puts all binary data on a heap which is shared between actors


I said already:

> [...] this would be semantically identical to not sharing anything.

Erlang's data sharing (and no, not all binary data, just over a certain threshold; if you want to nitpick, be diligent and precise) is merely optimization trick, highly uninteresting when it comes to discussing type systems (because its semantics are identical to not sharing anything at all).

BTW, if you talk about Erlang, use proper Erlang's terminology. Erlang doesn't have "actors", it has "processes".


lol really? haha, nice bait. I have to go read it now.




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

Search: