HNHacker News
TopNewBestAskShowJobs

jondgoodwin

86 karma · joined September 8, 2017

submissionscomments
jondgoodwin··on Data races in Python, despite the Global Interpreter Lock
You claim that a language can guarantee completely deterministic runs. How is that possible in Vale?
jondgoodwin··on Weakening Cycles So That Turing Can Halt
Important mistype. It should read: "The proof does NOT stop us from knowing that SOME programs will or will not halt.
jondgoodwin··on Weakening Cycles So That Turing Can Halt
Total functional programming indeed is another example of a valid approach to weakening cycles and thereby guaranteeing termination. Although it works for that, it is too restrictive for my taste. I am looking for less restrictive forms of weakening that allow creation of a broader range of algorithms (including "imperative") that we can still guarantee will terminate.
jondgoodwin··on Weakening Cycles So That Turing Can Halt
It is indeed grand and delightful. I am glad you enjoyed the post so much. It was every bit as much fun for me to grok and then and share with others.
jondgoodwin··on Weakening Cycles So That Turing Can Halt
AIUI actors are regularly idle. However, you are right that Pony offers a clever mechanism not offered by Erlang, which allows an actor to effectively despawn itself. I believe how it does this is to notice when no other actor has a reference to it. If no other actor has a reference to it, no one cannot send it any messages. If it has no messages in its queue and it is idle (not currently dispatched on a message), we know it will never again receive any messages, and therefore it is safe to free itself because it will never again have work to do.
jondgoodwin··on Weakening Cycles So That Turing Can Halt
Author here. You are 100% correct that Pony makes a strong claim about being deadlock-free: "It’s deadlock free. This one is easy, because Pony has no locks at all! So they definitely don’t deadlock, because they don’t exist." (from the first page of the tutorial). Sylvan Clebsch is a really smart guy and Pony is a stunning piece of engineering based on rigorous analysis. He would surely know.

So far as I can determine, this part of the claim is true: it makes no use of locks, not in the runtime and none are surfaced to the Pony programmer. The only synchronization mechanism that Pony makes use of is the MPSC queues that make possible message passing between actors. Each actor has its own queue, and it is only "active" when it has messages on its queue that need to serviced. The work-stealing scheduler will give every actor with messages an opportunity to process at least one message. When it does so, it never blocks and (hopefully) finishes with no requirement to return a result to any other actor (although it may be pass messages to other actors if it wishes).

Now consider Wikipedia's definition of a deadlock: "a deadlock is a state in which each member of a group is waiting for another member, including itself, to take action, such as sending a message or more commonly releasing a lock". Notice that deadlocks can occur not only because of locks (which Pony does not have), but also because of waiting on another actor to send a message. The wiki article lists four conditions for a deadlock, which (it turns out) can also occur in a message-passing architecture.

How would Pony trigger this sort of deadlock? Consider implementing the dining philosophers problem in Pony by having the main actor spawn five fork actors (with on-table state) and then five philosopher actors, telling each the fork actor to their left and the fork actor to their right. The philosopher actors all wake up hungry, so they reach for their left fork first, by sending it an acquire message and then effectively suspend. If the left fork A is in on-table state, it changes its state to indicate it has been acquired by a specific philosopher and sends a message back to the philosopher to say it has been acquired. That reactivates the philospher to now send an acquire message to the right fork B. But maybe by this point in time another philosopher has already acquired that right fork B as its left fork! So it sends a message back to the requesting philosopher to say it is not currently available to be acquired, try again later.

If you walk through this implications of this carefully, you will see that although every philosopher is getting activated by messages regularly, at a certain point in time it is possible that meaningful forward progress can cease for at least one philosopher. At least some philosophers will starve, because they become deadlocked in not being able to get two forks needed to eat, because they are effectively contending over access to shared resources.

The situation is semantically equivalent to when we use locks for forks instead. And if we apply Dijkstra's partial order to how the philosopher actors acquire their forks in an actor-based message passing architecture, the deadlock risk vanishes and all the philosophers have a reasonable chance, eventually, to eat and therefore guarantee eventual forward progress.

Does this explanation of an example satisfy your question?

jondgoodwin··on Weakening Cycles So That Turing Can Halt
Author here. Cool story about odd perfect examples. That said, my post is not trying to find a way to crack the halting problem, and thereby demonstrate it is not real. Turing wrote a most excellent proof, and I stand by it wholeheartedly. I even cite another famous numeric example of a program we still do not know if it will terminate for all numbers: the Collatz conjecture.

Notice my description: "Turing proved that no general algorithm can be formulated that can answer this question across all possible programs." The operative part here is "across ALL possible programs". The proof does stop us from knowing that SOME programs will or will not halt. It only stops us from being able to determine this for EVERY possible program. My post explores a very specific subset of programs that we can prove will terminate, then asks what pattern(s) underlie such programs, and then explores the use of such patterns in a variety of interesting problems. It is this last result that most intrigued me, and caused me to write about it.

jondgoodwin··on Compiler Performance and LLVM
Hey - I am thrilled to hear about your positive experience with interning strings. I never actually did a performance test, so I am delighted to hear your gains were substantial.

As for you questions about performance on bigger source files and twiddling optimization options, I too am curious about that. I will likely revisit those questions at some point in the future. It will be easier to do once I have baked these diagnostics into the compiler.

jondgoodwin··on Cone Programming Langauge
Absolutely agree.
jondgoodwin··on Cone Programming Langauge
Did you also read the follow-on post on transitional permissions?
jondgoodwin··on Cone Programming Langauge
Very well said. This is very much what I am after. Some common idioms in Rust or C++ just feel unnecessarily verbose to me (e.g., `<exp>.unwrap().borrow_mut()`), and I am looking for straightforward ways, often borrowed from other languages, to express the same intent more succinctly and clearly.
jondgoodwin··on Cone Programming Langauge
Thanks. I always welcome feedback and take it seriously.
jondgoodwin··on Cone Programming Langauge
Yes, borrowed references being lifetime-constrained means that I have a "borrow checker" that ensures that. It is only partially implemented.

You are correct that Cone supports a static, shared, mutability permission, including on borrowed references into resizable arrays. The short safety answer is array resizing is only possible when you have a unique reference to the array, so you can't run into the trouble you describe. I wrote a post about it.[1]

You left out an important clause I specified in my criteria: "with no chance of exception". Terminating the program in the event of dereferencing a reference does not meet the safety requirements I set for Cone references.

Yes, only borrowed reference have lifetime constraints. I did not mention the allocator-based reference in that quote because of context. Cone does support a distinction between move vs. copy types. Unlike with Rust, the distinction is typically inferred from the definition of the type. Currently, all memory is "pinned", but that may become more flexible in the future.

The safety strategy for Cone involves versatility: giving the programmer a curated collection of permissions and memory allocators, each with distinct advantages and disadvantages. The safety of certain options can be completely determined statically, making them inflexible but fast. Others will use a mix of static and runtime mechanisms, which offer greater flexibility but incur a runtime cost.

That said, I admit I am somewhat uncomfortable temporarily injecting a borrowed reference into a longer-lived container as snippet 4 shows. I feel like any logic able to ensure this is only done safely would be too complicated for my taste, at least for now. I understand how your mechanism would address this scenario, but again that does not ascribe to my more restrictive notion of safety. If the program does it wrong, it crashes.

Thanks for the added insight into your design choices and your kind comments. I will certainly look through your links. [1] http://pling.jondgoodwin.com/post/interior-references-and-sh...

jondgoodwin··on Cone Programming Langauge
> There is no available reference type that can target objects from different allocators.

Cone actually does support Rust-like, lifetime-constrained borrowed references which can do exactly that safely. Cone also supports raw pointers (however de-reference safety is the responsibility of the programmer).

I appreciate the chance to learn about your language's unique form of reference type. I am less likely to call them safe than you, no doubt because I use a different criteria for safety. A key requirement I have placed on references (vs. pointers) is that you can always de-reference them and get a valid value with no chance of exception. I don't think your references would comply with this.

A Cone programmer would need to use raw pointers to throw off the shackles of lifetime constraints but, unlike with your references, they could not expect such pointers to turn into nullptr if the object they refer to has been freed. Given the nature of Cone's design, there is no way to accomplish this mechanic with decent performance, especially given that borrowed references and raw pointers are both able to point inside an allocated object.

I do appreciate your bringing it to my attention and wish you all the best with getting others to learn about and adopt your language.

jondgoodwin··on Cone Programming Langauge
Yes, but that's not what I meant in that quote. Cone is not ready for any use right now. So, I am making no effort to market it right now. When it is at least MVP (at least a year or more away), I will get more serious about marketing, including especially for 3D web.
jondgoodwin··on Cone Programming Langauge
Cone is an imperative, multi-paradigmatic language in the family of systems programming languages (C, C++, Rust, D).

It is fundamentally statically-typed. However, a language that is too rigidly typed can sometimes degrade programmer productivity. Abstractions like variant types and various forms of type polymorphism can improve code flexibility and reuse, which is why I plan for Cone to include these features (the home page has a link to a page that describes this in more detail).

High-level attributes of a language are always hard to get right, because terms mean different things to different people, but several responders do a better job than I did of explaining why concise and readable don't necessarily have to be contradictory goals, at least for me. My primary aim here is that code be maintainable. By concise, I am actually far more focused on how much of a function's logic can fit readably on the editor window without scrolling than I am the size of keywords. Certain common C++/Rust patterns feel unnecessarily verbose to me (e.g., borrowing a reference in Rust), and I am trying to incorporate syntactic patterns from a number of other languages that I feel encode the same intent consistently in a way that a programmer familiar with Cone will be able to process and edit more quickly. Of course, that's always a judgement call...

jondgoodwin··on Cone Programming Langauge
A summary of key differences from Rust: A richer collection of build-in memory management strategies (e.g., tracing GC), Pony-inspired permissions (esp. safe shared, mutable), structural subtyping (as well as nominal), and a bunch of features intended to improve ease-of-use and productivity. At some point, I will write up a page on my web site to explain Cone better for someone coming from Rust (or C++ or ..).
jondgoodwin··on Cone Programming Langauge
It is memory safe in the same way as Rust is. Rust allows you to de-reference a raw pointer, but only within an explicitly de-marked `unsafe` block. Cone will require a similar explicit mechanism. If you want the compiler to check your code for memory safety, don't use this mechanism. If you do use it, the responsibility for safety within rests on you, the programmer.
jondgoodwin··on Cone Programming Langauge
There is no connection. I was unaware of the similarity to UCF's logo until recently. It is something I will need to replace, as much as I like how it looks.
jondgoodwin··on Cone Programming Langauge
That's a fair critique, and I will edit the website to make that disconnect between current reality and aspiration clearer (more than the disclaimer I have on the home page). Because there is so much left to do, I have made no effort to market the language for any sort of use. So, I got caught flat-footed that a website I am still building up piece by piece, primarily for personal clarity and private communications, has gotten premature publicity. I will adjust accordingly.
jondgoodwin··on Gradual Programming
I appreciate the clarification, as I did not catch that from the context. I just assumed maybe you were not aware of my follow-up work with Cone.

I do think there are good research opportunities in these ideas, e.g.:

* Type theoretic work on formally proving the soundness of the mechanics (as a follow-on to the proof work done with Pony and Rust-belt).

* Cross-allocator comparative studies of performance and other factors (although many such studies have been conducted in the past, the fact that you can control for the language/runtime and even test hybrid memory management strategies would make a new study a worthy addition to prior work).

* Assessing the impact of borrowed references and lexical memory management on tracing GC's "generational hypothesis"

In your role at Stamford, perhaps you can inspire students to pursue such projects. My focus is devoted to real-world results, but I would be happy to offer support, if that would be of any help.

jondgoodwin··on Gradual Programming
> Several of the axes mentioned (memory management, language specialization) lack any documented attempts to systematize their treatment at the language level.

This is not entirely true. The author of the Gradual Memory Management paper you cite is currently building [1] a systems programming language called Cone [2] that incorporates these mechanisms. Although much work remains to be done, the online reference documentation does go into some detail about the syntax and semantics for references, allocators and permissions.

[1] http://github.com/jondgoodwin/cone [2] http://cone.jondgoodwin.com