F# and BitC have a lot of similarities. Both are functional-imperative languages that have adopted eager evaluation. At first glance, the main difference in the languages is that F# traces its origins to O'Caml while BitC is more closely traced to Haskell (though ironically we started with something more like an imperative ML). The other big difference, of course, is that F# is a CLR language. On the one hand, this gives F# the ability to integrate with some very large bodies of code in very useful ways, and that's a big plus. On the other hand, it means that F# has adopted some unfortunate compromises to its design because of some things that CLI can't express.
In a lot of ways I think that Don may have made the right decision on that, and given how minor the "missing" bits in CLI are, I think it's possible to imagine that CLI may evolve to close the gaps. The questions that I want to explore for a moment here are (a) how are BitC and F# different, and (b) is the difference enough to justify a new language given the available options *today*? Some obvious differences: 1. F# targets CLR. BitC (mostly) targets native code, though we're clearly going to need a run time loadable and expandable intermediate form. 2. I believe that BitC is more committed to static compilation. While I certainly don't *object* to a JIT, and will probably implement one, the language design goal is to be able to do a fully static compilation no later than application install time. This "late compile" approach is regrettably necessary if we are to support generic code in libraries. and retain the ability to version our libraries. 3. BitC is going to push region and effect typing, which F# hasn't tackled yet. 4. As a matter of design bias, BitC probably favors unboxing more strongly. E.g. we will implement an unboxed union type. 5. BitC's adoption of literal kinds gives us a bunch of forms of type genericity that can't be expressed in other languages 6. BitC *may* enable mutability inference - we still have an ongoing discussion about this. 7. *Because* BitC is not limited by CLI, we will be able to preserve genericity in places where F# cannot. Notably: we probably won't need the distinction between late-bound and early-bound type variables, and we will be able to preserve genericity in a reasonable fashion over (e.g.) basic arithmetic operations and algorithms that are built from this. 8. BitC's type constraint system is first class (type classes) and user-extensible (the type classes aren't "baked in". 9. I expect that we will actually maintain type rules for BitC. I've been looking, and I can't find those for F# anywhere. I may or may not have time to do a formal semantics; that's something I would welcome help on. 10. One can imagine doing a native-compiling implementation of F#. Given the expressiveness limitations inherent in CLI, and the fact that these are inherited by F#, I don't believe that we can write a truly high-performance kernel in F#. Unfortunately, that differentiator becomes rapidly less compelling as we move up the software stack. Things that are flatly unthinkable in a kernel become both necessary and commonplace just one or two layers above that. 11. Unless we proceed merrily down the dependent type rathole, BitC will adopt much of the "kind classes" ideas of Habit. I need to have an offline talk with Mark Jones before making any real decision about that. 12. BitC's mixfix mechanism is more powerful than F#'s closest equivalent, and blending it with an F#-style expression quoting mechanism will make it more so. 13. BitC places a more careful emphasis on the value, use, and support of unboxed types. Because of the instance resolution and instance coherence issues that plague type classes, it's clear that the BitC approach to type classes needs to evolve away from Haskell a bit. BitC needs to pay more attention to module import hygiene. At the very least, this means that *importing* a type class instance and opening it into the current instance resolution environment need to be different operations. It also means that instance resolution needs to be performed w.r.t. an explicitly manipulable instance environment. We're going to have to break some new ground here. I also think that it has to be asked whether type classes are actually buying us all that much. Multivariable type classes have a bunch of issues, and in practice all of the useful cases we have seen to date are ones that are baked in to the compiler. If it turns out to be true that all of the useful cases are single variable type classes, then the marginal benefit of type classes is much reduced. It ends up being the ability to retrofit operators to types after the fact. That's useful, but perhaps not overwhelmingly compelling. *IF* that's where we end up, then I think we need to consider the possibility that we should drop the notion of post-hoc operator binding and settle for a simpler, purely lexical mechanism. One of the under-appreciated advantages of operator methods is that they have a preferred affiliation with the 'this type. This affiliation offers at least some of the benefits of type functions without much of the icky mess. That being said, there seem to be numerous examples in the Habit report where two-variable type classes are demonstrably useful. I'm not [yet] inclined to throw this particular baby out with the bath water. To summarize, yes, I *still* think there is value in pursuing a new language, though I think that value is less clear than it may have been before F# emerged onto the scene. Politically, I think that a non-CLR language has a much higher chance of adoption in the Linux world, and that is not a small thing. shap
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
