7 ms·
As a regular Pony user, and coding seriously in it for a few months, this is what I think; I rather fight the Reference Capabilities (easily the hardest aspect
by niclash 6y ago
As a regular Pony user, and coding seriously in it for a few months, this is what I think;
I rather fight the Reference Capabilities (easily the hardest aspect of Pony and probably the number one reason people give up) than to spend endless amount of time CHASING concurrency problems, or even worse, HOPING that I didn't forget some lock/mutex/whatever and ending up having data corruption.
Pony is forcing me to do the right thing, and doesn't allow me to "I guess I could get away with X", and this reassurance is a huge boon.
It is hard to learn, and if you are not in the concurrency space, don't know what a thread is and don't care much for data integrity, then Pony is not for you. The effort you need to put in will not be appreciated by you.
If you have a strong opinion on how things must be done, Pony is not for you, because it won't allow you to follow your opinion all the time, because the opinion is not safe.
Pony is not for everyone, but for those that can think in the Pony model, then it is an incredible tool to ensure your code is correct, safe and performant.
- niclash 6y agoAnd the Pony community has helped me out at every turn of confusion and getting my head twisted into the Pony model. Big kudos to them...
- ibraheemdev 6y agoThis sounds a lot like someone learning Rust. Both languages solve similar problems with very different solutions that come with complexity overhead.
- ivanbakel 6y agoPony and Rusts' solutions to the concurrency problem are almost identical - forbid shared mutability through the type system. In what way are they very different?
- niclash 6y agoI am not an expert in Rust's mechanics and only looked at it superficially, but I got the impression that shared references can't be guaranteed (to not exist in mutable ways) all the way through an object graph. I am not surprised if I am wrong about that. It wasn't the main deciding factor for me... My primary factor was "Actor Model" and I was struggling with Erlang's lack of static types, so that put Pony in the focus. An Actor Model framework on top (I recalled there was one for Rust) had given me "questionable" results with Akka (due to compromises/constraints in the JVM and Java/Scala). HTH
- ibraheemdev 6y agoThere are a couple of Rust actor frameworks, the most popular being actix [0] and bastion [1] 0: https://github.com/actix/actix https://github.com/actix/actix 2: https://bastion.rs/ https://bastion.rs/
- haggy 6y agoWhat issues did you run into on the JVM with Java/Scala? I spent 5 years working up and down the entire akka stack so I'm curious to learn from your point of view. Also did you try akka typed or classic?
- anko 6y agoI'm not the parent poster but I'll have a go. Please feel free to correct me if I've got parts wrong, I'm hoping to learn something too. In other languages, lets say Erlang as an example, actors themselves do not have concurrency concerns. The receive loop/handler just executes everything as though it's single threaded. The code is very easy to reason about. It also applies backpressure in that if your synchronous loop is blocked, your mailbox will fill up. If you need concurrency, it's done by talking to other actors, which can be processing on another thread under the hood. But the thread part of it is managed and you are not dealing with threads per se, you just know that if you have multiple cores and you send a message to another actor, it can be scheduled to run on another core safely. If you want to run a bunch of tasks in parallel, you could use a pool of actors up to around the number of cores you have, and the parallelism is at maximum the number of actors in the pool. Sorry if i'm over explaining, I just wanted to set the stage. One of the benefits of this arrangement is if something is going slowly you can order the list of actors by biggest mailbox and you can see where your bottleneck is. And if you are using a lot of memory you can just order the actors by the memory usage and you can see where the big state lives. With akka actors, instead of just dealing with the actors and actor pools, they suggest you make actors non-blocking. The way you do this is with Futures. Suddenly all the simplification of the actor model goes out the window. It mixes an async programming style with an actor model that doesn't need to be async! So you have the negatives of asynchronous programming and very few benefits of the actor model. I realise How do you identify the bottlenecks of the system? Maybe your execution context is full - actually I'd love to know how people debug their execution contexts in general. Last I checked, execution contexts would spawn new threads as well, so not only are they heavyweight (compared to erlang processes) but you have the operating system schedule them instead of the thing that knows how to best schedule them which is your language runtime.
- mcguire 6y agoRust is essentially C++ with restrictions that make threads safer. Pony is a completely new language based on the actor model where "threading" is a first-class operation and the type system is formally designed to make guarantees that make threads safer. Pony really wants you to think differently about your problem and solution.
- staticassertion 6y agoWhile Pony is awesome, I think what you describe is a weakness and not a strength. If Pony were to move more of its hardest concepts to standard libraries, it would be a far simpler language, even if it maintained the actor/behavior concepts. Much of Pony can be done with Arc/Mutex/&/move in Rust, but with special syntax, and it's that special syntax that kills the language frankly. You can implement actors in Rust pretty easily. I've done it multiple times, including in a way that provides a pony-like nominal interface. It isn't as powerful, and it isn't as efficient, because frankly I'm not very good at this sort of thing and don't have time to work on it, but it's possible. What pony gives is some syntactic sugar in some important places (the actor keyword, the be keyword) and a very strong runtime.
- OkayPhysicist 6y agoThe "move the hard parts to standard libraries" approach is exactly the approach Elixir and Erlang take. The OTP (the standard library for Erlang, and called seamlessly from Elixir) provides abstractions for almost every use case you'll ever need. It's super easy to write Elixir/Erlang without ever righting an explicit "receive" statement.
- pjmlp 6y ago> Rust is essentially C++ with restrictions that make threads safer. And saner defaults for type safety. As much as I enjoy C++, the safety defaults due to backwards compatibility are mostly wrong.
- agumonkey 6y ago^ seconded
- throwaway894345 6y agoAt least with Rust, very few domains involve so much parallelism that one benefits from the overhead that the borrow checker adds to the development process. And many times the borrow checker is completely inadequate at preventing race conditions (frequently the case with distributed computing). Of course, Rust can recoup those losses elsewhere, by having better tooling or competing in domains where performance matters a lot, but I’ve not found the safety to be worthwhile in my domain. EDIT: s/data races/race conditions
- nextaccountic 6y ago> And many times the borrow checker is completely inadequate at preventing data races (frequently the case with distributed computing). The borrow checker (in safe rust) always[0] prevents data races. It can't, however, prevent race conditions (but neither can pony do[1]) [0] https://doc.rust-lang.org/nomicon/races.html https://doc.rust-lang.org/nomicon/races.html [1] https://www.ponylang.io/faq/#data-race https://www.ponylang.io/faq/#data-race
- throwaway894345 6y agoRight, I should have said "race conditions"; it hadn't occurred to me that the two weren't synonymous. My point wasn't that Pony does prevent race conditions, but rather that non-data-race race conditions are much more common in my domain (distributed computing) or really any domain where multiprocess architectures are common so I don't benefit much from the static guarantees that Rust affords.
- staticassertion 6y agoPony does not prevent race conditions. Two actors can wait forever for the other to send a message, deadlocking.
- mateo411 6y agoIs deadlock considered a race condition? I typically think of a race condition an issue with concurrency where data might be modified by another thread which causes the program to return incorrect results.
- strogonoff 6y agoFrom my observation (as a curious non-user), all safe languages seem to include certain escape hatches. They guarantee safety, but if you know what you’re doing there’s always a %FEATURE% that opts you out and allows anything, including shooting yourself in the foot (getting a panic at runtime, etc.). From your experience with Pony, which escape hatches did you notice? How would a Pony programmer shoot themselves in the foot?
- spooneybarger 6y agoC FFI.