12 ms·
Show HN: Fo: An experimental language which adds generics on top of Go
- sagichmal 8y agoC++ style (compiler) or Java style (boxing) implementation?
- en4bz 8y agoLooks more like C style macro token pasting with sugar.
- kodablah 8y agoFor generics: How do recursive types and self-referencing types work? What about generic types that themselves require generic types? Can type constraints be applied? What do generics look like on interfaces? How about in slices? When compiled, are specialized functions written or is the code shared? How is runtime reflection for type params implemented? Also, oblig ref of a now-defunct lang on top of Go: https://oden-lang.github.io/ https://oden-lang.github.io/ Finally, good work, I hope it was fun! Don't take criticisms too seriously, they are good things (as opposed to silence) and par for the course on this site.
- bigato 8y agoYou really missed the opportunity here to call your language Foo
- polymathist 8y agoAuthor here. I've been working on Fo part time for 4 months. Feel free to ask me anything.
- politician 8y agoWhat does the implementation look like under the hood? What are the limitations of your approach (i.e. generic interfaces) and are they fundamental or just on the todo list?
- deckar01 8y agoHere are a couple diffs that leave out the copied code: https://github.com/albrow/fo/compare/faf3c9f96a8ecd9d17ca968deff8e91bbb1a70fc...f9ce4c22557028f969d9b4292b3dac0f1b7f05e7 https://github.com/albrow/fo/compare/faf3c9f96a8ecd9d17ca968... https://github.com/albrow/fo/compare/f76c531f839e5e76e5f6b7f424943cf45b823e06...master https://github.com/albrow/fo/compare/f76c531f839e5e76e5f6b7f...
- webkike 8y agoIt's very likely monomorphizing the types, i.e. creating a unique type for each generic invocation.
- polymathist 8y agoThe Fo compiler parses and type-checks Fo source code and then generates and outputs Go code. It generates a unique concrete type for each usage of a generic type. You can look at the examples directory of the repo to see what this output looks like: https://github.com/albrow/fo/tree/master/examples/box https://github.com/albrow/fo/tree/master/examples/box. Generic interfaces are pretty fundamental IMO. It's something I plan to add to the language before the v1 release.
- Analemma_ 8y agoDoes this have anything in common with Go besides the language syntax? Is it binary-compatible with Go?
- 8y ago
- gggguil 8y agoShouldn't it have been called Ho ?
- tonyedgecombe 8y agoInteresting, now all you need to do is add exceptions :)
- jitl 8y agoGolang already has an exceptions-equivalent construct in the shape of panic() and recover(): https://blog.golang.org/defer-panic-and-recover https://blog.golang.org/defer-panic-and-recover You’re free to write exception-full code using those constructs, although the community tends to use error return values for the most part.
- bb88 8y agoThis is how I understood the use for panics: https://stackoverflow.com/questions/44504354/should-i-use-panic-or-return-error https://stackoverflow.com/questions/44504354/should-i-use-pa... > You should assume that a panic will be immediately fatal, for > the entire program, or at the very least for the current > goroutine. Ask yourself "when this happens, should > the application immediately crash?" If yes, use a panic; > otherwise, use an error. In Java, say, exceptions are the standard for raising a normal error. A class of those exceptions are runtime errors which are equivalent of "panics". Yes you can handle them, but they denote a problem with the program that can't be solved by the interpreter (divide by zero error, etc)
- ithkuil 8y agoIf want (and if it makes sense) you can use panics as a control flow mechanism to quickly bubble up errors inside your implementations. See an example in the standard library itself: https://golang.org/src/encoding/json/encode.go https://golang.org/src/encoding/json/encode.go, line 295 What's frowned upon is leaking this out of your package's interface/contract.
- bb88 8y agoThen it strikes me kind of like C++ exceptions. They have them, and it's kinda supported, and there are certain things you shouldn't do with them, so everyone just uses return codes. Java/Python encourage the use of exceptions as returning error conditions, rather than return error codes.
- gtt 8y agoI liked certain aspects of Go, but lack of generics was a deal-breaker for me. You approached it a way better than I (and many others) did. Instead of arguing on forums you started writing code.
- awb 8y agoIsn't interface{} a generic?
- gowld 8y agoThat's reflection not generics. It's mostly the same denotational semantics, but much less efficient performance.
- mirkoadari 8y agoI think it's more than that. You wouldn't commit code that doesn't compile. Your entire organization, however, will troubleshoot the code that fails on runtime in production.
- tree_of_item 8y agoIt's not the same semantics at all. Using the top type is not even close to using a type parameter.
- ajkjk 8y agoNo? Generics are type-checked at compile time.
- andrewstuart2 8y agoNo, you have to use reflection to determine the type at runtime. Generics use the compiler to prove the type at compile time so that the runtime can forego the much-slower reflective code paths.
- thanatos_dem 8y agoNoooooo! interface{} is a raw type. It’s like “Object” in java land. It has no meaning in its own right, and needs to be carefully checked whenever you want to actually use it. The proliferation of interface{} across the go ecosystem is really unfortunate, and will be hard to correct once generics are finally supported. I haven’t dug too far into the Fo code yet, but I’d guess that it’s doing something akin to type erasure in Java, and adding conversions and type checks transparently when compiling down to a go binary. Sort of like how if you ever pop open a class file and dig into it, you’ll never see any references to generics. Everything compiles down to objects in the end with generated type checks.
- jcelerier 8y agobut go already has generics https://www.reddit.com/r/rust/comments/5penft/parallelizing_enjarify_in_go_and_rust/ https://www.reddit.com/r/rust/comments/5penft/parallelizing_...
- tomp 8y agoGo actually has generics. Just not for user-defined methods and types.
- reificator 8y agoIf you're referring to the map type, that is implemented in plain Go. (Though it does import "unsafe") . There are no generics like you would see in other languages. https://golang.org/src/runtime/hashmap.go https://golang.org/src/runtime/hashmap.go https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics https://dave.cheney.net/2018/05/29/how-the-go-runtime-implem...
- nemo1618 8y agoWell, it's not quite fair to say it's "plain Go." The compiler converts expressions like x, ok := m["foo"] into function calls. User-level code can't define syntax sugar like that. Also, the hashmap implementation imports some internal packages, so you can't just copy and paste it. (I would know, because I mostly did copy and paste it for one of my own projects: https://github.com/lukechampine/randmap https://github.com/lukechampine/randmap)
- reificator 8y agoWhen discussing whether go has generics, "plain go" is a reasonable thing to say. Besides it's a compiler. It's going to take an input in format X and translate it to an output in format Y. That's just what they do. Syntactic sugar debates aside there's still no generics in there.
- 8y ago
- weberc2 8y agoThis is suuuper cool. I've thought of doing something similar for a while, but I tried approaching it from the "generate Go" angle. I also found the Go syntax too tedious to write a parser for (because I've never written a parser before, nor any kind of compiler, so the learning curve was too steep). So I was just going to try to build a simple, expression-based language that compiled to (and interoped with) Go. Unfortunately, I ran out of steam because the learning curve was so steep.
- nemo1618 8y agoOne approach would be to use the existing Go parser packages and modify them to suit your needs. Unfortunately (last time I checked) the standard library packages for this (go/ast, go/types, etc.) differ from the actual packages used by the Go compiler. But they might be close enough to suit your needs.
- pravj 8y agoDidn't know that the compiler itself isn't using the same packages after going in a bootstrapped fashion. Using the existing packages is a great approach as I think that Go standard library has one of the best packages supported for AST/lexing/parsing family, in comparison to Python and Ruby. Haven't worked with Rust.
- weberc2 8y agoI recall experimenting with that, but I had a hard time making them work correctly (although I don't recall the details--might've been something to do with their parser DSL or something). The compiler doesn't use the stdlib because the compiler was originally implemented in C, and then they did a mechanical C -> Go translation.
- stunt 8y agoNice work!
- jstimpfle 8y agoNice work. But, serious question - When going with parameterized types I know from Haskell how you always end up needing one more language extension and always end up banging your head against the wall that separates types and values a little more. At least if you're not a math genius, but probably even then. And from Java I know that there's a pretty trivial example that showcases how its Generics implementation is unsound when mixed with inheritance. And I know that the Go maintainers have been hesitant for a long time because they didn't know a good version of Generics to add. So, is there any version that just works, and never leads the user down any rabbit holes? And that doesn't lead to ever increasing type boilerplate? Because I've been super happy ever since I decided that worrying about occasional usage of void pointers in C is just not worth my time. And where configurability is really needed, function pointers are totally fine - I don't think there is any need for static polymorphic dispatch (function pointers are probably even preferable, to avoid bloated machine code).
- pjmlp 8y agoCLU was the first language to implement generics in 1975. There are many levels of generic capabilities, across multiple languages in about 45 years of research, we don't need the full shop, CLU generics would already be quite usefull versus interface{} everywhere.
- ben509 8y agoHaskell is a proving ground, so it's picked up a number of ideas that never quite panned out. I think you can identify a core set of features that are pretty reasonable. I think that'd be type classes, constraints, and functional dependencies. If they made a handful of extensions standard (GADTs, etc.) it would mostly Do What You Want without a lot of prodding. > And from Java I know that there's a pretty trivial example that showcases how its Generics implementation is unsound when mixed with inheritance. I'd be curious to see that. There's a well known limitation that mutable containers (and they're all mutable in Java) need to be invariant, but that doesn't make them unsound. The type system was also already unsound due to covariant arrays and nulls being a member of all classes, but if you don't break those rules or disable checks, Java generics work as far as I can tell. By "work", I mean I've yet to get a ClassCastException in a fair amount of work with some gnarly Java generics. And, really, 99% of the boilerplate in Java's typing is that you can't declare aliases for types; that seems to be more due to engrained hostility to syntactic sugar than any technical difficulty. > So, is there any version that just works, and never leads the user down any rabbit holes? Most of the "gradual typing" projects for languages like Javascript, Python, Ruby all seem to accomplish what you're looking for, by virtue of the fact that you can just ignore it when you don't want it.
- dagss 8y agoHas anyone worked on Lisp-like macros in Go? Executing code at compile time to emit AST and compile it.. That is what I feel is really missing. Even with strictly a compile-time phase (no run-time macro evaluation) it could be quite useful. Starting with generics seem to lead down the dark path of C++ template metaprogramming.. I would rather do something like type StrBox = MakeBoxType!(string) ...and have clean hygienic macros to generate my "generic". Syntax candy can be added to that to get generics...but starting with generics and only supporting that went really really badly for the C++ ecosystem.
- kodablah 8y agoCompletely agree. Go has parsing and type checking and what not as part of its stdlib. However they choose a code generation approach which is a separate step and often relies on code comments. Even if security fears of compile time execution were allayed, the Go stewards are very unlikely to support altering the very strict-yet-simple grammar for multiple reasons. Macros would be very welcome, but they can't help improve the language if the language is intentionally inflexible.
- gliese1337 8y agoIs there any support for bounded type variables? Or plans to add them?
- polymathist 8y agoYes, see https://news.ycombinator.com/item?id=17305563 https://news.ycombinator.com/item?id=17305563
- jeffrallen 8y agoShould be called mofo.
- pjmlp 8y agoIt would not be a good idea in Portuguese speaking countries (mold).
- symlock 8y agoThe only time I find I need generics is when I'm prototyping things and making lots of changes. Node, Ruby, & Python are great for this. In fact, PHP's associative array is really powerful/sloppy since it can be used as a list, hash/dictionary, iterable, or object. That aside, I don't think I've ever really been bothered by the lack of generics for actual work code.
- marcrosoft 8y agoI've been working full time in Go since 2012. I've never had a use for generics.
- jimbokun 8y agoAnd I've read about many people using Go and wishing for generics from day one.
- jjoonathan 8y agoHow does Go statically type check collections, then? It seems like a pretty common, desirable use-case to me. I could understand not missing this if you're coming from a dynamically typed environment, but understand that many people aren't.
- marcrosoft 8y agoUmm don't? Why are you iterating over unknown types?