Compared to e.g. Rust (one of the better modern examples of easy rigorous math) I really like how concise they are. What I'm missing are saturating operations. I know some people find them useless, and through a "perfect results" lens they are, but they still give you the closest representable number and they are intuitive for humans since that's how most analog instruments work
This bit from the About page is notable: "never write a programming language. That’s like rule #1. Everybody will just tell you it isn’t needed and then argue about syntax."
I agree for the hello world but I disagree with the syntax. It is the first thing you see and the characteristic you can never escape. It is like the layout and typesetting of a text: the substance is of course more important, but it is still very important. I personally find much more readable languages that have a concise-but-not-too-much syntax, that use not too many special characters, and that is read like fortran/pascal/c/etc (I don't how to define it, but for example lisp is different)
I don't think that Pony is claiming to be novel in the area of syntax?
As far as I can tell reading here, “reference capabilities” don’t do anything that properly-used C semaphores haven’t done for near half a century. Or that their abstraction of that isn’t nicer to use than, say, Elixir’s, or better than Rust’s borrow checker for managing mutability. A code example could convince me otherwise.
Show us code that uses “reference capabilities” to do something. This “the syntax doesn’t matter” talk just comes off as bullshit to devs wanting to actually use a language. It would be better to commit to a syntax, post some damn examples on the site, and let devs get used to “reference capabilities.” If the syntax needs revising, just do that in Pony v2.
If you want devs to be enthusiastic about your language, make it easy for them to understand why they should be enthusiastic. That means code, front and center, first thing.
True, it just means that it's idiotic, rather.
https://www.ponylang.io/discover/why-pony/
Syntax doesn't really come into it.
Edit: I'm as fond of discussions of the design of programming language syntax as everyone else - just in this case the apparent novelty of Pony is at a more fundamental level.
Playground: https://playground.ponylang.io/
They're on HP https://www.ponylang.io/ unfortunately the article link points to /discover/
It seems really bizarre to respond to “there should be easily-accessible examples of code that demonstrate the language’s key features on the website” with “there’s a $200 conference in South Carolina where there will be a talk on it.” Honestly, it comes across as not just bizarre, but somewhat disrespectful (though I’m sure that was not your intention).
Printing hello world is the default of the industry for this sort of thing.
The Rust playground defaults to "Hello World" but that's just because there has to be something there, it's not on the home page of the website or anything (though it used to be).
Mainly my point is it’s weird to complain about hello world. It’s been the first program for languages for decades.
You also don't get to be the chief decider of what all of us may or may not talk about.
It’s crazy how many people build something and make a website for it, only to hide the thing they’ve built somewhere deep in the website. Just show me the damn thing!
I would be torn if I had to write intro documentation like this. On the one hand, people demand code examples, but on the other hand, the majority of people reading code examples will nitpick minor pet peeves in the syntax and completely detract from the actual new ideas and concepts that go way beyond just the syntax.
I found the descriptions of the concepts very enlightening and I honestly think they gave me a better idea of what the language would “feel like” to program in than a code example (or a description of the syntax) would have.
In theory, syntax should be interchangeable. It's conceivable to parse a syntax into an AST and reexpress it in another syntax without changing the AST. In practice, this is not done for many reasons (incl. tooling like diffs) but a big reason is that individual bits and bobs of the syntax are tied to the new concepts in subtle ways. There could absolutely be multiple syntaxes for the same concept, but if the concept is new, even in small and unobvious ways, then no prior existing language’s syntax will map it exactly. For this reason, a code example can't really express the new concept, especially if the syntax is superficially similar to another language that doesn't actually have that concept.
I believe that, regardless of our personal preferences, the reality is that syntax is a major criteria for adopting a programming language.
Some people have trouble following Lisp code, and won't touch your project if it looks like chat. Others will have the opposite reaction and have their interest captured instead.
Err, ok, so? Don't be so afraid of criticism, I guess? Yeah, some people will nitpick. I don't see the problem.
So by seeing the syntax up front I can save a lot of time because in a world where there are many languages that do the same thing it really boils down to using the one with the syntax that you like the most.
Wat? If all languages were just syntax re-skinning, we really wouldn't need more than one compiler backend...
Generally the semantic differences are much more important. Rust isn't interesting for its syntax, it's interesting for its ownership rules and borrow checker. Erlang isn't interesting because of its syntax, it's interesting for its actor model concurrency. And so on...
But just because syntax is superficial doesn't mean that it isn't important. If a language has such poor syntax that I feel the need to write my own compiler to work around its syntax, I have to seriously question the skills and/or motivations of the author. If I am capable of writing a compiler at the syntactic level, why not just go all in and write my own compiler that implements _my_ desired semantics? A language that I find subjectively distasteful at the syntactic level is nearly guaranteed to be filled with semantic and architectural decisions that I also dislike. Consider Rust, I do not think that its syntax and abysmal compilation times can be decoupled. I would rather write my own borrow checker than subject myself to writing rust. And the reason is not the syntax, which I do strongly dislike, but the semantic properties of the language, such as horrible compilation times and compiler bugs (if a language has more than 100 open issues on github, I consider it broken beyond repair).
I mean, you do you. No one is judging. The fact remains that Rust exists primarily because there are some features that C++ cannot reasonably provide
It seems, from some skimming of the first like 10 pages of the guide, that Pony is an object-oriented language with actors, and a built-in concept of mutability of references. What kind of references are there? You say that deadlock is impossible; how — do you have session types or something? You say that nulls don't exist; how — do you have linear typing? How do you express capabilities?
Essentially, give me a one-page overview of the static and dynamic semantics (i.e. type system and runtime semantics) that gives me all I need to know about this language to decide whether I want to learn more about it.
The language looks cool, but all documentation I've seen so far seems to assume that the reader doesn't even know what static typing is. To get knowledgeable people interested, I think it's useful to have a pitch that appeals to people who are already familiar with a bunch of languages.
Its original designer, Sylvan Clebsch, is nowadays working at Microsoft Research on languages like Verona [0], the last paper he contributed to, which has Guido as well among the collaborators, is about adding regions to dynamic languages, using Python as example implementation,
https://www.microsoft.com/en-us/research/publication/dynamic...
[0] - https://www.microsoft.com/en-us/research/project/project-ver...
https://www.microsoft.com/en-us/research/project/project-ver...
Maybe they are now mostly behind MS walls, or have indeed decided to look elsewhere for their research goals.
https://www.ponylang.io/discover/
to
On the second link, as another commenter mentions, the "Try it in your browser" is one click away, near the top. On the first link, it's two clicks away, but the first of those clicks is a perhaps surprising backwards-lick to get back to the homepage...
Unfortunately, many of the diehard language enthusiasts here seem to be getting quite worked up over how inaccessible the code examples are. Instead of being able to immediately see the syntax so they can rush back here to make insightful and educated comments on how that syntax compares to $their_fave_lang, they are forced to spend up to 4 or even 5 minutes reading documents clearly describing the design of the language, and being obliged to click on their mouses up to 10 times even in some cases.
If a member of the Pony team sees this: even though it's more than a tad ridiculous and you have in fact made a lovely website with loads of clear information, maybe consider adding the "Try it in your browser" link as another option in the burger menu thing on the left. That way it follows everyone around, and you never have to suffer a HN discussion getting needlessly derailed by the resident PL fanatics.
The problem with the linked docs on the Pony website is not that it doesn't explain the semantics (it does!) but that it seems to be written at a pace appropriate for someone who has no clue what static types even are. [1] Give a concise demonstration of the syntax and the semantics, even if that means that the latter will use terminology that not everyone will understand. Then the full tutorial is there for the details.
One of the innovative point of Pony is the iso reference. iso reference means that an object graph is accessible from only that iso reference. It avoids sharing mutable data.
This is more nuanced actually. And it could have implications and contradictions with "get stuff done". IfI can have a non-provable piece of code that serves me well 99% of the time I could save coding time at the expense of correctness and could fit the bill for my use case.
We get a lot of stuff done assuming P != NP, that no polynomial-time prime factorization algorithm for classical computers exists, that one-way functions exist, etc.
As long as assumptions are clearly stated and are routinely questioned it's fine to have them
The causality model was great, but is there a way to handle backpressure now?
Sylvan Clebsch is now working on Project Verona[1].
0. https://ponylang.zulipchat.com
1. https://www.microsoft.com/en-us/research/project/project-ver...
Not a great look, although it looks like it was only deprecated 2 weeks ago, so I'll give them a pass.
Maybe a third-party awesome list or so would be interesting.
Other than that, I guess one could get involved in the community to ask questions about things one needs for some project, or search more specifically for things one needs and hope to then find them.
Pony – High-Performance Safe Actor Programming - https://news.ycombinator.com/item?id=25957307 - Jan 2021 (152 comments)
For those who enjoy long form video interviews, here is Kris Jenkins of Developer Voices interviewing Sean Allen on Pony language
Does pony guarantees forward progress in all cases? Does it means that if I tried to implement a python interpreter in Pony it will statically reject the implementation? Requires me to submit a proof of deadlock freedom with any program I feed the interpreter? Or any python program running on this interpreter is magically free of deadlocks?
edit: as an aside, deadlocks have little to do with locks.
1. https://blog.jtfmumm.com//2016/03/06/safely-sharing-data-pon... 2. https://bluishcoder.co.nz/2017/07/31/reference_capabilities_...
Still, trading deadlocks for livelocks is a net negative as they are harder to identify and diagnose.
How could that be true? You'd be emulating the language particularities, so deadlocks would be just virtual states. Your interpreter itself being free of deadlocks doesn't mean it cannot represent them.
It's like thinking that you cannot write e.g. console emulators in Rust, because people typically ship unsafe code to consoles, yet Rust enforces memory safety. Yes, it does enforce it - so you'd be representing unsafe accesses instead, rather than actually doing them.
For example I can define a notsemaphore actor that calls a callback once an internal count reaches 0, and then I can forget to decrement it and so it will never reach 0. But technically this didn't involve synchronization so there isn't a stack trace to tell me why is my program stuck and somehow this is better.
So what does it means that Pony is deadlock free if it can implement deadlocking programs?
A better, more rigorous claim would be that the pony runtime is deadlock free or that there are no primitive blocking operations.
I'd be hesitant to call this a "Pony runtime" property - to my understanding language runtimes just provide application bootstrapping and execution time standard library access. Pony code becomes machine code, managed by the OS as a process with some threads. This language property guarantees you that those threads will never "actually", "truly" deadlock. Code implemented on the Pony level can still progress if it chooses to do so, and that Pony formally ensures it always has the option to choose so.
If your business requirements necessitate otherwise, that's a different matter, something you introduce and manage on your own.
I'm not sure if there are any languages that allow you to pass down language constraints specifically, maybe Lisp or similar can do that? But then often that wouldn't actually be helpful, these requirements usually come from the outside (like in your Python example, it comes from Python being specified that way).
For most everyone who aren't trying to implement the possibility of deadlocks in guestcode, this remains a useful property even without that.
If I click "why pony" i want to know when to use it. I want to decide for myself if I want to use this
I couldn't find a page where it's clear if I should invest my time in it
How to do this: - examples - companies/projects who use X - what this language aims to do - what this language is good at
So checked Exceptions like Java?
https://patterns.ponylang.io/data-sharing/isolated-field
Basically what I gather is:
1. Actors are like threads, but have data structures associated with them. Actors have functions like methods associated with them called "behaviors", which are called asyncronously. BUT, any given Actor will only ever have one thread of execution running at a time. So calling a "behavior" is like sending a message to that actor's thread, saying, "Please run this function when you get a chance"; "when you get a chance" being when nothing else is being run. So you know that within one Actor, all references to Actor-local data is thread-safe.
2. They have different types of references with different capabilities. Think "const *" in C, or mutable and immutable references in Rust, but on steroids. The extra complexity you do in managing the types of references means that they can get the safety guarantees of Rust without having to run a borrow checker.
So in the above example, they have a Collector actor with an internal buffer. Anyone can append a character tot he internal buffer by calling Collector.collect(...). Code execution is thread-safe because the runtime will guarantee that only one thread of Collector will run at a time. The data is of type 'iso' ("isolated"), which ensures that only one actor has a reference to it at any time.
Once the internal buffer gets up to 10, the Collector will transfer its buffer over to another Actor, called a Receiver, by calling Receiver.receive(...) with its own internal buffer, allocating a new one for subsequent .collect() calls.
But its internal buffer has a reference of type 'iso', bound to Collector. How can it transfer this data to Receiver?
The magic is in these two lines:
let to_send = _data = recover Array[U8] end
This creates a new local variable, to_send. Then it atomically:- makes a new Array[U8] of type iso
- assigns this new array t; Collector._data
- Assigns the old value of Collector._data to to_send
Now Collector._data has a new reference of type iso, and to_send has the old one.
Next we do this:
_receiver.receive(consume to_send)
The "consume" ensures that to_send can't be referenced after the consume call. So the compiler can verify that Receiver.receive() will be the only one able to access the old value of _data that we passed it.Sounds like an interesting approach; it would be nice to see more examples of realistic patterns like this; perhaps simple sequential programs broken down into multiple actors, or things like a simple webserver implementation, with some sort of shared state.
not hard, kids
It's great that you have all that philosophy behind it, all sounded great, but if you don't show me a compelling example in the first minute or two, not even in tutorial, then you'll fail to capture my interest.
https://tutorial.ponylang.io/types/actors
If you know a few programming languages I think you should be able to guess what the syntax does from context.
And then the next key idea is here:
https://tutorial.ponylang.io/reference-capabilities/referenc...
(Although I think the first actual interesting I idea I saw was "Destructive read" under https://tutorial.ponylang.io/types/classes#functions , but that's clearly just an isolated quirk, not part of the core idea of the language.)
Playground: https://playground.ponylang.io/
They're on HP https://www.ponylang.io/ unfortunately the article link points to /discover/
The programming language documentation wasn't written for an audience primarily composed of programmers? That would be an odd choice.
Most people visiting such websites are programmers who are more often than not busy as all hell.
If you show me 10 lines of code and a mini flow-chart demonstrating how Pony's actor runtime does stuff better then I'll definitely be intrigued and go browse the website for longer time (and more carefully). Is that a "shitty behaviour in society"?
But if the maintainers / creators do in fact want to give homework to visitors then that's their prerogative and their right. But as the other poster has said, I owe them no more than one minute of my time and they are not making a good use of it.
Yours is a confusing take for me. Glad you have all that free time though. I don't. My curiosity lasts one minute because I am only looking for game changers, not another endless hobby to sink time into. And if you can't intrigue me that way then I am out.
Would I be missing out on stuff by doing things that way? Very definitely! But, well, I can't worry about everything.
Apparently not too busy to visit HN and post shallow dismissals.
I agree with GP. Not everything is for everyone and expecting every project to cater to your very specific needs is rather entitled. If you're not interested, feel free to move on - I do that all the time for most of the content on here.
Indeed, as you have just excellently demonstrated. I did not dismiss anything, I generalized, which I believe we're all aware is never accurate. Thought that much was obvious and did not warrant a response like yours.
> If you're not interested, feel free to move on
Exactly what I did, and then I and a few others explained why. No idea why that was met with emotional responses that classify mine and others as "shitty behaviour".
"Please don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something."
> The difference between an actor and a class is that an actor can have asynchronous methods, called behaviours. We’ll talk more about that later.
Who wrote this[1]? The Doctor?
[1] https://tutorial.ponylang.io/getting-started/how-it-works
It's statically and strongly typed, and super concurrent. It's a very different vibe than anything python.
No. Modern mutex implementations [1] are extremely efficient, require only 1 byte of memory (no heap allocation), and are almost free when there's no contention on the lock – certainly much faster and much lower latency than sending messages between actors.
[1] Like the parking_lot crate for Rust.
I think sending messages is more about the way you think about concurrency, more than the implementation.
I have always found the "one thread doing "while True receive message, handle message" much easier to reason about than "remember to lock this chunk of data in case more than one thread should access it"
[1] at the very least you will need one queue for each cpu pair, but that's yet another layer of complication.
https://www.erlang.org/blog/parallel-signal-sending-optimiza...
That's a valid point of view, but Pony's claim to which I objected is about performance, not ease-of-use or convenience.
No, you also need synchronization operations on the sending and the receiving end, even if you have a single sender and a single receiver. That's because message queues are implemented on top of shared memory – there's no way around this on general-purpose hardware.
Lockfree spinlocks will only waste cycles on one CPU. A huge difference when you have dozens and hundreds of cores.
Because modern mutexes are so cheap (only 1 byte directly in the data structure, no heap allocation), you can do very fine-grained locking. This way, a mutex will almost never be contended. Keep in mind that a reader waiting on an empty queue or a writer waiting on a full queue will also involve syscalls.
> […] and likely stalls all the CPUs on your machine.
Huh? Where did you get this idea? Only the waiting thread will be blocked, and it won't "stall" the core, let alone the entire CPU.
By the way, if all your threads are waiting on a single mutex, then your architecture is wrong. In the equivalent case, all your actors would be waiting on one central actor as well, so you'd have the same loss of parallelism.