HN user

tyoverby

325 karma
Posts1
Comments50
View on HN
How Rust is tested 9 years ago

Here's an example scenario:

1. Your PR is tested with the merge against Master. All green!

2. Another PR is tested with the merge against Master. All green!

3. The other PR goes in first. All good!

4. Your PR goes in (merge happens, but introduces a bug). Oh no!

Growing fibers 9 years ago

Another thing that I should mention is that most langauges, features like generators / async / exceptions don't compose well at all. In a language where these features are implemented through continuations, it's really easy to pick how they interact, leading to some really powerful tricks!

Growing fibers 9 years ago

The page that you linked to shows off some features that are not really found in any major programming langauge. Time-traveling search is a big one for me.

Many languages have exceptions, but with shift/reset, you can implement your own exception handling behavior trivially, including things like resumable exceptions.

Some languages have async/await, but almost all of those implementations are state-machine based, which means that they don't compose well when used with more complex language features like generics and higher order functions.

But more than that, in continuation-based asynchronous programming, "async" functions are just normal functions that execute in an async prompt. Here's an example of a multi-user asynchronous TCP echo server in my toy language with tagged delimited continuations:

    async {
      loop {
        let conn = accept_connection("localhost", 9999)
        async {
          loop {
            let data = conn.next_data()
            conn.send(data)
          }
        }
      }
    }
Where all of those asyncrhonous constructs (including `async` itself) are really short wrappers around delimited continuation machinery.

You'll notice that the nested calls to `async` indicate that there are two asyncrhonous contexts

1. Connection acceptance happen on their own "thread" of control

2. Each connection gets their own context in which everything is internally asyncrhonous

Growing fibers 9 years ago

I've been playing around with delimited continuations in a toy programming language of mine for a while now and I seriously think that its a paradigm that will eventually take over the scripting language space. First-class control flow is so powerful once you get the hang of it!

I think the generalization of "use-after-free" to "use-after-invalidation" is the most important

I wonder if this sort of vulnerability is possible in Rust

Rusts borrow checker is designed for the more general case of "use-after-invalidation" and `free` is treated as a simple invalidation of what happens to be a heap allocated structure.

Interestingly, the borrow checker also prevents invalidations that are still common in memory-safe languages such as iterator invalidation.

Let's say that you and I both create a library. You try to publish your C++ library to the standard debian repository, and I'll try to publish mine to cpam, npm, pip, etc...

If you actually manage to get your library included, then we can compare how long it takes to update your library.

The most important part of language tooling for me is reproducability. I should be able to do the following to any project:

    git clone <project name> && cd <project name>
    <build tool> build
And have it fetch all of that projects dependencies, and then build the entire system.

Anything that requires machine-wide package installation is immediately disqualified (user-wide package installation is almost as bad).

Autocomplete is most commonly used on structures in order to find out which fields and methods that structure contains.

If you used an s-expression based grammar that still had fields and methods, then you'd get the exact same experience.

    foo.bar. <- autocomplete here
vs
    (foo.bar.)
            ^ autocomplete here

I don't see why they would be any better or worse than another grammar choice.

It might be true that s-expressions would make people prefer certain semantic decisions that would be difficult to analyze for autocomplete.

Hello, I work on the C# compiler and we use a handwritten recursive-descent parser. Here are a few of the more important reasons for doing so:

* Incremental re-parsing. If a user in the IDE changes the document, we need to reparse the file, but we want to do this while using as little memory as possible. To this end, we re-use AST nodes from previous parses.

* Better error reporting. Parser generators are known for producing terrible errors. While you can hack around this, by using recursive-descent, you can get information from further "up" the tree to make your more relevant to the context in which the error occurred.

* Resilient parsing. This is the big one! If you give our parser a string that is illegal according to the grammar, our parser will still give you a syntax tree! (We'll also spit errors out). But getting a syntax tree regardless of the actual validity of the program being passed in means that the IDE can give autocomplete and report type-checking error messages. As an example, the code "var x = velocity." is invalid C#. However, in order to give autocomplete on "velocity", that code needs to be parsed into an AST, and then typechecked, and then we can extract the members on the type in order to provide a good user experience.

My personal opinion is that everyone should just use s-expressions. Get rid of this whole debate :P

I'm not ChicagoDave, but what he wrote resonates with me.

I view my blog as an extension of my memory. When I write things, I do it mainly for myself, rather than to appeal to other readers. Because of this, my blog gets practically no traffic. I'm happy with github hosting my ramblings for free.