# Design Notes for the Fine Language This language is being designed as I go, because the main thing I'm interested in is building something that's fun and productive for me personally. That means, rather than being super careful, I'm just building the thing that pleases me at any given moment. Here are some notes. The notes are for me in the future, in case I'm wondering why the language is one way instead of another way. ## The `new` keyword I really like rust's "just use a type name with curly braces to construct new values". It's really clean! Unfortunately it leads to an ambiguity in the syntax that I don't like: ``` rust if something { ... ``` In the code above, after I have parsed `something` and I see `{`, am I: - Parsing an object construction expression for the type `something`? - Parsing `something` as a boolean value reference and `{` as the start of the block? Naively you would expect the latter, but if I scan ahead a little more: ``` rust if something { foo: true }.foo { } ``` Rust does not allow `struct` literals in the condition of the `if`, which is correct, but that's more work than I want to do here. There's just a lot of context flowing around about whether or not I can parse a structure literal in any particular situation. The `new` keyword is a compromise: we know that the context immediately following the `new` keyword is always a type expression, so we know that e.g. `<` or whatever means "generic type parameter" and not "less than". ## Patterns and Alternate Types Instead of `enums` or inheritance, we're using an alternate type like in Typescript, with `or` between types. See the `alternates.fine` test for a work-up of the types and syntax and whatnot. I think it works pretty well. Actually using alternate types involves pattern matching, either one at a time, with the `is` operator, or in bulk, with the `match` expression. `match` can check for completeness, but `if/is` cannot. Patterns are VERY simple, and are explicitly *not* destructuring right now. (Destructuring brings up a whole lot of complexity that I don't want to deal with.) Patterns are basically: ``` (identifier ":")? type_expression ("and" )? ``` The identifier at the front represents a binding of the value being considered as if it were of the same type as the type expression; the identifier is in scope for the optional predicate after the "and" and so you can use it as if it were the type because, well, that part of the pattern already matched. As a special case, the identifier is *also* in scope for the body of an `if` expression when an `is` expression is used as the condition. ``` if b is c:Foo { result = result + c.a; // c should still be in scope! } ``` `match` is the multi-value pattern matching expression, like this: ``` match b { c:Foo -> c.a, _ -> 0, } ``` The special pattern `_` always evaluates to true. Note that unlike rust we do not allow variable binding, e.g., in rust you can write: ``` match b { d -> ..., } ``` but in fine you need to write: ``` match b { d:_ -> ..., } ``` The reason is that the rust version is ambiguous: if `d` matches some value already in scope (e.g., an `enum` arm) then the arm is matching if b == d, but if `d` is unbound then `d` becomes a variable declaration. This is a spooky action-at-a-distance and I don't approve of it. # Complete Garbage ## Lambdas/Closures/Anonymous Functions Looking for a syntax here; I want to keep `fun` as a declaration like `let` and not let it enter the expression space. I don't like fat-arrow syntax because it makes expression parsing very ambiguous, potentially requiring a lot of lookahead. (TODO: Is that true?) Maybe a leading character like ` \x => x+1 ` or ` \(x,y) => x+y `? ## Interfaces/Traits/Whatever These are incomplete structural types. Methods are easier to make compatible than members, but members should also work so long as they are strict prefixes of the thing. What about sound casting with narrowing? That's union types baby, do we really want those? It could be neat if we're doing otherwise structural-compatibility. ## On Objects and Classes Sometimes I think it should all be structural types. Maybe later there can be anonymous types that match shapes.