6 ms·
Author here. I've been working on Fo part time for 4 months. Feel free to ask me anything.
by polymathist 8y ago
Author 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?
- zokier 8y agoIt seems to compile ("transpile") to Go, and then invoke Go compiler on the generated source. So I guess that would make it also binary compatible? https://github.com/albrow/fo/blob/master/main.go#L70 https://github.com/albrow/fo/blob/master/main.go#L70
- stansm 8y agoBriefly looking at source one can tell it just transforms Fo into Go and invokes go run
- weberc2 8y agoAny plans to add formal sum types (as opposed to interface hacks)?
- polymathist 8y agoDefinitely something I'm thinking about. It's one of a handful of features that I have in my head but haven't created an issue for.
- weberc2 8y ago> haven't created an issue for You have one now: https://github.com/albrow/fo/issues/7 https://github.com/albrow/fo/issues/7 :)
- nemo1618 8y agoHi there! I worked on something similar a while ago: a compile-to-Go superset that adds some generic functions/methods. You may have come across it: https://github.com/lukechampine/ply https://github.com/lukechampine/ply My perspective was that when I find myself wishing for generics in Go, what I really want is not full-blown generic types and functions, but rather a few helper functions like map/filter/reduce, or converting a map to a slice, etc. Having "true" generics is undoubtedly useful when you really need them, but the Go ecosystem has shown that they aren't strictly required in order to write large, maintainable programs. And you pay for them in the form of misuse. In that sense, I view generics much the same as operator overloading. Anyway, I ran into some tricky edge cases when working on Ply and I'm curious how you address them. First, Go lets you define local types, i.e. with a function scope instead of top-level scope. You can't define methods on these, nor can you reference them in top-level functions. How does Fo handle the case where I want to call a generic function/method on a locally-scoped type? The second issue I ran into was imports. I didn't devote a ton of time to this, but it seemed like it could be tricky to properly fetch both Go and Ply packages and pre-compile the Ply packages to Go. How does Fo handle this?
- polymathist 8y agoPly looks really cool! I can certainly understand the appeal of that kind of approach in terms of simplicity, stability, and better interop. Local types are an edge case I'll need to spend more time working on. The type-checker won't have any problems; the real question is how to generate the appropriate Go code. One solution might be to move the local type into a higher scope during code-generation. Another might be inlining the relevant generic types in the same scope as the local type. Finally, the best solution might just be to say this sort of thing isn't allowed and the compiler will return an error. Imports aren't supported right now, but it's one of the most important things I need to work on next. It'll be pretty tricky, but I'm confident I can find a solution. The fortunate thing about the approach I'm using with Fo is that I have complete control over the parser, type-checker, and code-generator. At the cost of having significantly more complexity, I have the flexibility to tackle these sorts of edge cases without relying solely on existing tooling.
- tclancy 8y agoDid you consider incrementing the first letter instead of decrementing when choosing a name?
- mustaflex 8y agoThe name would be "Ho", maybe he did.
- bakul 8y agoDid you consider parameterized packages? The idea is you can declare a set of related objects/types/methods as well as have concrete type specific initialization. E.g. package stack[t] type Type []t func New() Type { return Type{} } ... Then it can be used so: import s “stack”[int] var s1 = s.New()
- pjmlp 8y agoJust as additional info to others, this is how Ada, Modula-2 and Modula-3 generics kind of work.
- weberc2 8y agoI’ve seen this in ocaml and always thought it strange. I think it’s useful, but binding it to a package seems odd since packages are units of code distribution or some such.
- nickcw 8y agoI think parameterized packages are a great idea. It would be a light-weight way of getting just a bit of generic code into go. I made gotemplate to explore that idea https://github.com/ncw/gotemplate https://github.com/ncw/gotemplate This requires a round of `go generate` for the actual code generation, but otherwise quite a similar experience. Having it built in would be great!
- polymathist 8y agoParameterized packages are interesting but they come with their own problems. It can get tedious if I want to use, e.g., a stack with multiple different types. They also lose some of the flexibility that comes with scoping type parameters to any function/method/data structure.
- leshow 8y agoCan you do ad-hoc or bounded polymorphism? What about recursive types?
- polymathist 8y agoYes, I've already been thinking about constraining type parameters to an interface. Internally, the type-checker considers type parameters to have underlying type interface {}. A constraint on a type parameter should be as straightforward as changing it's underlying type to a specific named interface instead of an empty one. The only tricky bit I can see is thinking about how this would work with generic interfaces or whether we should allow other kinds of type constraints (e.g., union types).
- leshow 8y agoIf it considers parametric types to be interface {}, is that a kind of type erasure? I don't know much about Go, but it's my understanding that interface {} types have an extra layer of indirection and are essentially just pointers.