1. 9
  1.  

  2. 2

    Interesting!

    Random bits of feedback:

    Tuples are like a structs with unnamed fields. In fact, at runtime they are actually structs with fields named 1, 2, 3, etc.

    From experience with Rust, I’d suggest naming fields as _1, _2 (that is, matching traditional definition of identifier), etc instead. Numbers make the implementation more complicated (which might be an ok tradeoff, but evolution-wise, it makes sense to start simple). In the IDE layer, “what is an identifier” is important question; if numbers are sometimes identifiers, you need contextual info to figure this out, and more special cases in completion and such. In the lexer, there’s ambiguity in foo.1.1 which can be lexed as two field accesses or a float literal. Rust now has a hack where it splits a float token into three in the parser, to make the syntax work.

    When a module imports another module, it only has to look at the defined type signature. This makes type checking embarrassingly parallel at the module level.

    Yay! To fully reap the benefits here, you also need to be careful to make compilation embarrassingly parallel at the file level within a single “library” (this mostly boils down to having fully qualified names in things, and avoiding fixed points in name resolution), and to make dependencies between libraries explicit (so that there’s explicit DAG of libraries, rather than a global, flat search path).

    PS: syntax highlighting & line wrapping of code examples seem broken, at least on iPad.

    1. 1

      From experience with Rust, I’d suggest naming fields as _1, _2 … Ah I wondered why some languages did this, that makes total sense. You just saved me a potential headache later down the line!

      Yay! To fully reap the benefits here, you also need to be careful to make compilation embarrassingly parallel at the file level within a single “library” (this mostly boils down to having fully qualified names in things, … If I understand this correctly, then that is my plan. Sasquaches’ imports map roughly to Java’s. All runnable code must exist within a module, which corresponds to a classfile. Modules are declared in files, each file can have many modules. Files map to packages, which resembles Rust’s modules:

      file: src/foo/bar/other.sasq
      // package here is foo/bar/other
      Other { ... }
      
      file: src/foo/bar/bar.sasq
      // When the file has the same name as the folder, it elides the second qualification. It acts like mod.rs in Rust, however
      // I prefer to use the same name as the folder so then you don't have to disambiguate between different mod.sasq
      // tabs in your editor
      Foo { 
          doWork = (): void -> { ... },
      }
      
      Fooz {
          // Might elide the "foo/bar" part or follow Rust's model and do self/Foo. Likely the latter
          use foo/bar/Foo,
          // Filename is included in the import path unless the file has the same name as the parent folder
          use foo/bar/other/Other,
          ...
      }
      

      avoiding fixed points in name resolution Not quite sure what this means.

      make dependencies between libraries explicit (so that there’s explicit DAG of libraries, rather than a global, flat search path) Absolutely, I plan on taking advantage of the Java module system + jlink for this instead of just using the classpath.

      PS: syntax highlighting & line wrapping of code examples seem broken, at least on iPad. Ah yeah I see that on mobile. I’m using a hosted platform for the site but I’ll see if I can fix it via CSS.

    2. 2

      Many of your decisions landed at the same place as my (abandoned) wibble project from a few years ago. I managed to avoid the tuple problem matklad mentions above by not having tuples at all, only structs. Function parameters are structs too. I think this can simplify some of the redundancy, and the awkwardness of “what do you call the unnamed 2nd field?” (Answer: It must have a name.)

      1. 1

        Ah cool I’ll have to take a look at it. I was considering just making functions take a struct, though I wasn’t sure about the performance impact. I suppose I could just remove the extra struct creation at compile time if possible.