12 ms·
Flix – A powerful effect-oriented programming language
- andoando 1y agoI like it. This is the first time Ive seen a new programming language demo that made me want to use it
- voat 1y agoI'd love to use Flix for something. It looks beautiful. But I'm a web dev, and never touch the JVM ecosystem
- Joker_vD 1y agoOh, but you can just transpile it to WASM using e.g. TeaVM [0]. Just add another build step to your bundler or whatever web dev uses nowadays to build apps. [0] https://github.com/konsoletyper/teavm https://github.com/konsoletyper/teavm
- phplovesong 1y agoJVM is a no-starter. The language looks nice tho, shame they built it on JVM.
- atemerev 1y agoI don't know, Kotlin, Scala and Clojure are quite successful.
- latexr 1y agoI don’t think they mean the JVM makes it a non-stater in general, but a non-starter for them.
- jorkadeen 1y agoThe JVM is a state-of-the-art virtual machine with multiple open source implementations, a large ecosystem, and a fast JIT compiler that runs on most platforms. It is hard to find another VM with the same feature set and robust tooling.
- withinboredom 1y agoYes… with a million weird environment variables that can affect your runtime.
- eikenberry 1y agoI think the problem is that it targets a VM instead of native machine architectures, not the quality of the VM. I also find the times I need to target a VM to be very limited as I'm generally writing code for a specific platform, not a cross platform application. Of course this will vary between developers.
- cmrdporcupine 1y agoTargeting JVM means not having to roll your own garbage collector. And bonus, you get a huge world of third party libraries you can work with. It's been over a decade since I worked on the JVM, and Java is not my favourite language, but I don't get some people's hate on this topic. It strikes me as immature and "vibe" based rather than founded in genuine analysis around engineering needs. The JVM gets you a JIT and GC with almost 30 years of engineering and fine tuning behind it and millions of eyes on it for bugs or performance issues.
- jorkadeen 1y agoI strongly agree. Java and JVM bytecode may not be our "cup of tea", but it is simply unrealistic to implement any runtime environment with comparable performance, security, robustness, and tooling. The only alternative is WASM, but they are not yet there feature-wise.
- esafak 1y agoDon't say you'd pick the PHP JIT!
- withinboredom 1y agoIt has an actual IR now… so theoretically it’s actually possible…
- satvikpendem 1y agoI'd use HipHopVM like Facebook instead
- pshirshov 1y agoGraal Native Image and you have your native binary.
- phplovesong 1y agoNever used graalvm. Does it produce a machine code, or is it packaging the entire JVM in a zip like file?
- artemonster 1y ago[flagged]
- phkahler 1y ago>> Flix is a principled effect-oriented functional, imperative, and logic programming language... >> Why Effects? Effect systems represent the next major evolution in statically typed programming languages. By explicitly modeling side effects, effect-oriented programming enforces modularity and helps program reasoning. Since when do side effects and functional programming go together?
- noelwelsh 1y agoFP isn't really about eliminating side effects. Controlled effects are fine. That's what an effect system does. Avoiding side effects is really just a side effect (pun intended) of older programming language technology that didn't provide any other way to control effects.
- tossandthrow 1y agoArguably FP really is about eliminating side effects. The research has sprung out of lambda calculus where a computation is defined in terms of functions (remember: Functional programming). Side effects can only be realized by exposing them in the runtime / std-lib etc. How one does that is a value judgement, but if a term is not idempotent, then you arguably does not have a functional programming language anymore.
- hocuspocus 1y agoEffect systems in FP languages give you precisely that: referential transparency.
- tome 1y agoFunny you mention that because that's exactly how my talk at ZuriHac 2025 started, video published just yesterday: https://www.youtube.com/watch?v=RsTuy1jXQ6Y https://www.youtube.com/watch?v=RsTuy1jXQ6Y
- noelwelsh 1y agoYou gotta ask the question: why does FP care about eliminating side effects? There are two possible answers: 1. It's just something weird that FP people like to do; or 2. It's in service of a larger goal, the ability to reason about programs. If you take the reasonable answer---number 2---then the conclusion is that effects are not a problem so long as you can still reason about programs containing them. Linear / affine types (like Rust's borrow checker) and effect systems are different ways to accommodate effects into a language and still retain some ability to reason about programs. No practical program can be written without effects, so they must be in a language somewhere. More here: https://noelwelsh.com/posts/what-and-why-fp/ https://noelwelsh.com/posts/what-and-why-fp/
- Jonovono 1y agoIf you are in the JS ecosystem, you should check out Effect TS (https://effect.website https://effect.website) It's a very fun time
- hocuspocus 1y agoEffect TS is monadic though, as it's a pretty direct re-implementation of Scala's ZIO.
- satvikpendem 1y agoEven though it's called effect, it has almost nothing to do with algebraic effects, which is what this language and others like OCaml 5 have, and so Effect TS is more like Haskell (as it came from fp-ts).
- Joker_vD 1y agoOn a language semantics note: the semantics of extending/restricting polymorphic records seem to follow Leijen's approach [0] with scoped labels. That is, if you have a record e.g. r1 = { color = "yellow" }, you can extend it with r2 = { +color = "red" | r1 }, and doing r2#color will evaluate to "red"... and if you then strip the field "color" away, r3 = { -color | r2 }, then you'll get back an original record, r3#color will evaluate to "yellow". Which IMO is the sanest approach, as opposed to earlier attempts of trying to outlaw such behaviour, preferably statically (yes, people developed astonishingly high-kinded type systems to track records' labels, just to make sure that two fields with the same label couldn't be re-added to a record). [0] https://www.cs.ioc.ee/tfp-icfp-gpce05/tfp-proc/21num.pdf https://www.cs.ioc.ee/tfp-icfp-gpce05/tfp-proc/21num.pdf
- pshirshov 1y agoAwesome, it even supports HKTs. Can't find any mentions of typeclasses though, are they supported? Give me typeclasses and macros comparable with Scala ones and I would be happy to port my libraries (distage, izumi-reflect, BIO) to Flix and consider moving to it from Scala :3 UPD: ah, alright, they call typeclasses traits. What about macros? UPD2: ergh, they don't support nominal inheritance even in the most harmless form of Scala traits. Typeclasses are not a replacement for interfaces, an extremely important abstraction is missing from the language (due to H-M typer perhaps), so a lot of useful things are just impossible there (or would look ugly).
- jorkadeen 1y agoFlix supports type classes (called "traits") with higher-kinded types (HKTs) and with associated types and associated effects. A Flix trait can provide a default implementation of a function, but specific trait instances can override that implementation. However, Flix has no inheritance. The upshot is that traits are a compile-time construct that is fully eliminated through monomorphization. Consequently, traits incur no runtime overhead. Even better, the Flix inliner can "see through" traits, hence aggressive closure elimination is often possible. For example, typical usage of higher-order functions or pipelining is reduced to plain loops at the bytecode level without any closure allocation or indirection. Flix does not yet have macros-- and we are afraid to add them due to their real (or perceived) (ab)use in other programming languages. We are actively looking for library authors and if you are interested, you are more than welcome to stop by our Gitter channel.
- exceptione 1y agoSorry to hijack, but since you are involved, can you explain why tail call optimization would incur a run time perf penalty, as the docs mention? I would expect tail call optimization to be a job for the compiler, not for the runtime.
- helix278 1y agoTCO (tail call optimization) is often confused with TCE (tail call elimination), the latter is a runtime guarantee whereas the former is a compiler's best effort attempt to statically optimize tail calls.
- lutzh 1y agoI looked and Flix a while ago and found it really interesting - so much so that I wrote an article "Flix for Java Programmers" about it. Might actually be a bit outdated by now.. need to look at Flix's recent development again. But if you're interested: https://www.reactivesystems.eu/2022/06/24/flix-for-java-programmers.html https://www.reactivesystems.eu/2022/06/24/flix-for-java-prog...
- jorkadeen 1y agoCool blog post! With your permission, I would be happy to add it here: https://doc.flix.dev/blog-posts.html https://doc.flix.dev/blog-posts.html The language has improved a lot in the years since the post. In particular, the effect system has been significantly extended, Java interoperability is much improved, and some syntax have been updated.
- lutzh 1y agoThanks! And of course you have my permission, I'd be honored if the post was included in that list.
- plainOldText 1y agoHeads up, the links to Paul Butcher's datalog posts are broken. The series can be found here now: https://paulbutcher.com/datalog1.html https://paulbutcher.com/datalog1.html
- jorkadeen 1y agoThanks-- I fixed the links!
- klabb3 1y agoWow what a gold mine your blog is. It’s like a more elaborate and well thought through version of thoughts that have been torturing me for years. Looking forward to reading it all.
- 1y ago
- exceptione 1y agoI am deeply impressed by the depth and breadth of this language. Algebraic data types, logic programming, mutability, all there from the get go. Another aspect that I love from their comparison table is that a single executable is both the package manager, LSP and the compiler. As I understand, the language server for Haskell has/had to do a lot of dances and re implement things from ghc as a dance between the particular ghc version and your cabal file. And maybe stack too, because I don't know which package manager is the blessed one these days. Not to shit on Haskell -- it is actually a very fine language. However, the best feature is a bit buried and I wonder why. How ergonomic is the integration with the rest of the JVM, from the likes of Java? AFAIK, types are erased by JVM compilers... With the concept of `regions` they have at least first class support for imperative interaction. Note: With the JVM you get billions worth of code from a high quality professional standard library, so that is a huge plus. That is why the JVM and .net core are IMHO the most sane choices for 90+% of projects. I think the only comparable language would be F#. I would love to see a document about Flix limitations in the JVM interoperability story. __EDIT__ - There is a bit of info here. Basically all values from Flix/Java have to be boxed/unboxed. https://doc.flix.dev/interoperability.html https://doc.flix.dev/interoperability.html - Records are first-class citizens.
- littleroot 1y ago>a single executable is both the package manager, LSP and the compiler oh my i just know you're going to love unison
- exceptione 1y agoThanks for giving me homework. :-)
- cdaringe 1y agothe silly insane pythonic whitespace significance and lack of formatter drove me nuts. LSP didnt work half the time. Loved the idea, will visit again, but it resisted me expressing my program. If they get rid of the whitespace malarkey (why do i have to say it it!?) and the dev tools spruce up, im all in baby
- eximius 1y ago`case Circle(r) => 3 * (r * r)` I, uh, think your math might need some checking :)
- tomtom1337 1y agoRelevant xkcd: https://xkcd.com/2205/ https://xkcd.com/2205/
- mcdow 1y agoAnyone have a good primer on what effect-oriented programming looks like and how it’s used? Feel free to shill your own blog!
- rendaw 1y agoIt looks like "effect" as in impure functions in a functional language? I.e. a new way of dealing with effects (global/hidden state mutations) in a language that makes the pure-impure distinction. I'm not entirely sure. I thought it was going to be something like contracts or dependent types or something.
- adastra22 1y agoNo. It is essentially resumable exceptions. You throw an exception saying “I need a MyAlgebraicType” and the effect handler catches the exception, generates the value, and returns execution to the place the exception was called from.
- helix278 1y agoBut entirely definable in user code, so an effect is essentially a set of possibly impure operations you can perform (like I/O or exception throwing), and a function that exhibits that effect has access to those operations. Of course the call sites then also exhibit that effect, unless they provide implementations of the effect operations.
- ww520 1y agoEffect system allows programmers to annotate expressions that can have certain effects, just like the type system annotating type information on them, so compilers can enforce effect rules just like enforcing type rules. For example for a type system, let a: Int // this says 'a' has the type Int a = 5 // compiler allows, as both 'a' and 5 are of Int. a = 5.1 // disallowed, as 'a' and 5.1 are of different types. Similarly for example for an effect system, let a: Int let b: Int!Div0 // 'b' is of type Int and the Div0 effect. let c: Int ... a = 1 / c // disallowed, as '/' causes the Div0 effect which 'a' not supported b = 1 / c // allowed, as both '/' and 'b' support the Div0 effect. The effect annotations can be applied to a function just like the type annotations. Callers of the function need to anticipate (or handle) the effect. E.g. let's say the above code is wrapped in a function 'compute1(..) Int!Div0', a caller calling it can do. compute1(..) on effect(Div0) { // handle the Div0 effect. }
- naasking 1y ago// Computes the delivery date for each component. let r = query p select (c, d) from ReadyDate(c; d) facepalm. Select should always come last, not first, haven't we learned anything from the problems of SQL? LINQ got this right, so it should look like: query p from ReadyDate(c; d) select (c, d) Very cool language otherwise.
- IshKebab 1y agoYeah PRQL also got this right and it's sooo much nicer.
- jorkadeen 1y agoIt is a fair point-- the implicit argument being that this allows `c` and `d` to be bound before they are used, and hence auto-complete can assist in the `select` clause. Nevertheless, the counter argument is that the form of a logic rule is: Path(x, z) :- Path(x, y), Edge(y, z). i.e. an implication from right to left. This structure matches: query p select (x, z) from Path(x, y), Edge(y, z). So the trilemma is: A. Keep the logic rules and `query` construct consistent (i.e. read from right-to-left). B. Reverse the logic rules and query construct-- thus breaking with decades of tradition established by Datalog and Prolog. C. Keep the logic rules from right-to-left, but reverse the order of `query` making it from left-to-right. We decided on (A), but maybe we should revisit at some point.
- naasking 1y agoI appreciate the desire for consistency and being able to lean on old textbooks and documentation. A couple of considerations since this is a new language where history and precedent should (I think) be less important if it leads to clarity and improved productivity: 1. I think way more people coming to your language will be familiar with SQL and it's problems than with logic programming and Horn clauses. 2. I think many people are now familiar with functional pipelines, where filters and transforms can be applied in stages, thanks to the rise of functional programming in things like LINQ and Java's Stream API. This sort of pipelining maps naturally to queries, as LINQ has shown, and even to logic programming, as µKanren has shown. 3. People don't type programs right-to-left but left-to-right. To the extent that right-to-left expressions interfere with assisting the human that's typing in various ways (like autocomplete), I would personally defer to helping the human as much as possible over historical precedent. 4. Keeping the logic fragment separate from the query fragment (option C) seems viable if you really, really want to maintain that historical precedent for some reason. My two cents. Kudos on the neat language!
- pmontra 1y agoProbably Elixir spoiled me but when I see enum Shape { case Circle(Int32), case Square(Int32), case Rectangle(Int32, Int32) } def area(s: Shape): Int32 = match s { case Circle(r) => 3 * (r * r) case Square(w) => w * w case Rectangle(h, w) => h * w } I wonder why not this syntax: def area(s: Shape.Circle(r)) = { 3 * (r * r) } def area(s: Share.Square(w)) = { w * w } def area(s: Shape.Rectangle(h, w)) = { h * w } area(Shape.Rectangle(2, 4)) The Int32 or Int32, Int32 types are in the definition of Shape, so we can be DRY and spare us the chances to mismatch the types. We can also do without match/case, reuse the syntax of function definition and enumerate the matches in there. I think that it's called structural pattern matching.
- akkad33 1y ago> can also do without match/case, reuse the syntax of function definition and enumerate the matches in there. I I think that is multi-methods
- ddellacosta 1y ago> The Int32 or Int32, Int32 types are in the definition of Shape, so we can be DRY and spare us the chances to mismatch the types I have to admit I don't see the distinction here in terms of DRYness--they are basically equivalent--or why the latter would somehow lead to mismatching the types--presumably if Flix has a typechecker this would be a non-issue. I use Elixir now at work and I have used Haskell and PureScript personally and professionally, which both support analogs of both the case syntax and function-level pattern matching, and in my experience the case syntax is often the better choice even given the option to pattern match at the function level. Not that I'd complain about having both options in Flix, which would still be cool, but I don't think it's as big of a benefit as it may seem, especially when type checking is involved.
- pmontra 1y agoBecause I might write enum Shape { case Circle(Int32), def area(s: Shape): In32 = match s { Not only I had to write something that the compiler already knows, but I typed a compilation error. The second type definition is there only to make developers write it wrong. It does not add any information.
- textlapse 1y agoTangential, but I have a basic question: What makes Aarhus (mainly its university/techhub) a powerhouse for Programming Languages? C++, C#/Typescript, Dart, etc all have strong roots in that one small area in Denmark. In general, I am curious what makes some of these places very special (Delft, INRIA, etc)? They aren't your 'typical' Ivy League/Oxbridge univ+techhubs. Is it the water? Or something else? :)
- wslh 1y agoLineage? Aarhus has a strong academic tradition in areas like logic, type theory, functional programming, and object oriented languages. Many influential researchers in these fields have come through there. I also think there's a noticeable bias toward the US in how programming language research is perceived globally. Institutions like Aarhus often don't invest heavily in marketing or self-promotion, they just focus on doing solid work. It's not necessarily better or worse, but it does make it harder for their contributions to break through the layers of global attention.
- mollerhoj 1y agoOur long winters + free education sure doesn't hurt either - what better way to spend the yearly 6 months of darkness than working on a new proglang?
- isntThatSth 1y agoSix months of darkness is a bit hyperbolic, to say the least. The sunshine, temperature and daylight situation in Denmark is on the whole comparable to what you'd find in Germany, the UK, and Northern France. Also, long winters? You're thinking about Canada. The daily mean temperature in Aarhus, Denmark in January (the coldest month) is 1.3 C (34.3 F). https://en.wikipedia.org/wiki/Aarhus#Climate https://en.wikipedia.org/wiki/Aarhus#Climate. By comparison, Montreal, Canada has a daily mean temperature in January of -9.2 C (15.4 F).
- bodzioney 1y agoYes exactly. Aarhus had Martin-Löf, Nygaard, etc. Similarly, INRIA has had many influential researchers as well as OCaml and Rocq. Talent (and exciting projects) attracts more talent. But that doesn’t mean it doesn’t exist in US. Penn, Cornell, CMU, MIT and others have had historically very strong PL faculty. My understanding is due to the nature of grants in US it doesn’t give faculty the same freedom to work on what they choose as in Europe. So you get different research focuses because of that.
- syhol 1y agoVery similar to the koka language. I hope these effect systems become mainstream.
- crowdhailer 1y agoI'm pretty confident they will become a common feature in functional languages. Unison, Roc, EYG also have some version. Then we just need to wait for the functional languages to become mainstream.
- chombier 1y agoA quick comparison of the two languages would be interesting, in case anyone has experience with both.
- bobvylan 1y ago[dead]
- miniBill 1y agoVery cool language. The standard library looks mostly sane, although it does have `def get(i: Int32, a: Array[a, r]): a \ r` which means that it must have some kind of runtime exception system. Not my cup of tea, but an understandable tradeoff
- evertedsphere 1y agono, that's a region variable if i understand correctly, so closer to a rust lifetime
- wk_end 1y agoIt is, but your reply seems like a non-sequitur. The point OP was making was that it doesn't return an Option or Maybe or anything like that, meaning that there's a failure case untracked by the type system.
- evertedsphere 1y agooh, right, i misunderstood
- jrrrp 1y agoJust looking at the language myself, but it seems that it treats out-of-bounds array access as a non-recoverable bug and panics [1, 2], whilst map access returns Option [3]. Exceptions are a language construct only to enable Java compatibility and not recommended otherwise [4], but that's not to say you couldn't implement your own try/catch using the effect system. `r` is a region variable as the sibling comment says. [1] https://doc.flix.dev/chains-and-vectors.html#vectors https://doc.flix.dev/chains-and-vectors.html#vectors [2] https://flix.dev/principles/ https://flix.dev/principles/ See also "Bugs are not recoverable errors" [3] https://api.flix.dev/Map.html#def-get https://api.flix.dev/Map.html#def-get [4] https://doc.flix.dev/exceptions.html https://doc.flix.dev/exceptions.html
- wk_end 1y agoI agree with OP that this seems a little unfortunate, even though it's pretty par for the course. "Bugs are not recoverable errors" is such a fuzzy idea. On the one hand, indexing an array with an out-of-bounds integer could just be considered a program bug. On the other, the point of making the indexing operation return an optional value is to force the program to handle that scenario, preventing it from being a bug. One of the examples they give of a "recoverable error" is illegal user input, but in the case of "the user enters an index and it might be invalid", the language does nothing to keep the recoverable error from turning into an unrecoverable program bug.
- Hashex129542 1y agoI hate lot of keywords.
- daxfohl 1y agoAny code agents work well with this or do we have to start thinking with our own brain again? Seriously though, looks like a cool language and makes me sad that LLMs will probably inhibit the adoption of new languages, and wonder what we can do about it.
- drewm1980 1y agoI have the opposite gut feeling about LLM's; I think they're going to break down the barriers to adopting new programming languages, since they'll lower the cost of porting code dramatically. The code in a language's standard library is probably enough to train an LLM on the new syntax, and even if it isn't, agents now observe the compiler output and can in principle learn from it. Porting code from one language to another doesn't require deep creativity and is, barring API aesthetics, a perfectly well defined task. It will be one of the first programming tasks to be perfectly automated by LLM's. We are going to have to use our brains again to start thinking about why we're doing any of the stuff we're doing, and what effects it will have on the world.
- daxfohl 1y agoI hope so! On one hand I worry about the training corpus being so overwhelmingly biased toward certain languages that everything else will be drowned out. On the other, I think there'll be a point where we realize "reasoning" LLMs are more proficient with the same tools that we are: sound type systems, reusable libraries, concise syntax, DSLs where they make sense, etc. that the end game will look much more like skilled, experienced, thoughtful engineering work rather than the first of ten billion autocomplete attempts that happened to get something that met the basic requirements.
- gavinray 1y agoThis a genuine and major reason why I stick to popular languages and tools now. With how increasingly automated my code authorship is, reliability and training data matter a LOT.
- cap11235 1y ago
- daxfohl 1y agoMinor nit: the semicolons! Especially in the yield examples, since there's no "return" on the last line, the disparity looks weird. That said, I like how the syntax isn't overly functional, and not too different from what we see in mainstream languages. I'd be fine with either braces or indentation, but the semicolons have to go!
- jorkadeen 1y agoWe plan to explore semicolon inference in the future; but there are a lot of dangerous corner cases to consider.
- plainOldText 1y agoThis language seems to be aiming high. Congrats! Looking at their code however, I'm realizing one thing Elixir got "right", in my view, is the order of arguments in function calls. For example, in Elixir to retrieve the value associated with a key in a map, you would write Map.get(map, key) or Map.get(map, key, default). This feels so natural, particularly when you chain the operations using the pipe operator (|>): map |> Map.put(key, value) |> Map.get(key) In Flix it seems one needs to write Map.get(x, map), Map.insert(x, y, map). I guess it follows in the footsteps of F#.
- jorkadeen 1y agoBut in Flix you can write: def main(): Unit \ IO = Map.empty() |> Map.insert("Hello", "World") |> Map.get("Hello") |> println So I am not sure what you mean? In general, if you like pipelines then you want the "subject" (here the map) to be the last argument. That is how it is in Flix.
- plainOldText 1y agoSorry, I wasn't clear. Yes, you can have pipelines in Flix, F#, OCaml, to me however placing the "subject" first feels more natural, as function signatures (not necessarily in pipelines) have a symmetry not encountered otherwise: Subject First: Map.put(map, key, value) Map.get(map, key) Map.get(map, key, default) Map.del(map, key) Subject Last: Map.put(key, value, map) Map.get(key, map) Map.get(key, default, map) Map.del(key, map)
- plainOldText 1y agoI think their DIDYOUKNOW.md file in the source code is worth showing in full, as it describes the language in a more compact form: --- # Did You Know? ## Language Did you know that: - Flix offers a unique combination of features, including: algebraic data types and pattern matching, extensible records, type classes, higher-kinded types, polymorphic effects, and first-class Datalog constraints. - Flix has no global state. Any state must be passed around explicitly. - Flix is one language. There are no pragmas or compiler flags to enable or disable features. - Flix supports type parameter elision. That is, polymorphic functions can be written without explicitly introducing their type parameters. For example, `def map(f: a -> b, l: List[a]): List[b]`. - the Flix type and effect system can enforce that a function argument is pure. - Flix supports effect polymorphism. For example, the `List.map` function is effect polymorphic: its purity depends on the purity of its function argument. - in Flix every declaration is private by default. - In Flix no execution happens before `main`. There is no global state nor any static field initializers. - Flix supports full tail call elimination, i.e. tail calls do not grow the stack. Flix -- being on the JVM -- emulates tail calls until Project Loom arrives. - Flix supports extensible records with row polymorphism. - Flix supports string interpolation by default, e.g. "Hello ${name}". String interpolation uses the `ToString` type class. - Flix supports the "pipeline" operator `|>` and the Flix standard library is designed around it. - In Flix type variables are lowercase and types are uppercase. - In Flix local variables and functions are lowercase whereas enum constructors are uppercase. - Flix supports set and map literals `Set#{1, 2, 3}` and `Map#{1 => 2, 3 => 4}`. - Flix supports monadic do-notation with the `let*` construct. - Flix supports "program holes" written as either `???` or as `?name`. - Flix supports infix function applications via backticks. - Flix compiles to JVM bytecode and runs on the Java Virtual Machine. - Flix supports channel and process-based concurrency, including the powerful `select` expression. - Flix supports first-class Datalog constraints, i.e. Datalog program fragments are values that can be passed to and returned from functions, etc. - Flix supports compile-time checked stratified negation. - Flix supports partial application, i.e. a function can be called with fewer arguments that its declared formal parameters. - the Flix type and effect system is powered by Hindley-Milner. The same core type system that is used by OCaml, Standard ML, and Haskell. - the Flix type and effect system is sound, i.e. if a program type checks then a type error cannot occur at run-time. If an expression is pure then it cannot have a side-effect. - the Flix type and effect system supports complete type inference, i.e. if a program is typeable then the type inference with find the typing. - The Flix "Tips and Tricks"-section https://doc.flix.dev/tipstricks/ https://doc.flix.dev/tipstricks/ describes many useful smaller features of the language. - Flix has a unique meta-programming feature that allows a higher-order functions to inspect the purity of its function argument(s). - Flix names its floats and integers types after their sizes, e.g. `Float32`, `Float64`, `Int32` and `Int64`. - Flix -- by design -- uses records for labelled arguments. Records are a natural part of the type system and works for top-level, local, and first-class functions. - Flix -- by design -- has no implicit coercions, but provide several functions for explicit coercions. - Flix -- by design -- disallows unused variables and shadowed variables since these are a frequent source of bugs. - Flix -- by design -- disallows allow unused declarations. This prevents bit rot. - Flix -- by design -- does not support unprincipled overloading. Instead, functions are given meaningful names, e.g. `Map.insert` and `Map.insertWithKey`. - Flix -- by design -- does not support variadic functions. We believe it is better to pass an explicit array or list. - Controversial: Flix defines division by zero to equal zero. - Controversial: Flix defines String division as concatenation with the path separator. For example, `"Foo" / "Bar.txt" => "Foo\Bar.txt"` on Windows. ## Standard Library Did you know that: - Flix has an extensive standard library with more than 2,600 functions spanning more than 30,000 lines of code. - the Flix Prelude, i.e. the functions which are imported by default, is kept minimal and contains less than 20 functions. - most higher-order functions in the Flix standard library are effect polymorphic, i.e. they can be called with pure or impure functions. - the Flix type and effect system enforces that equality and ordering functions must be pure. - the Flix standard library uses records to avoid confusion when a function takes multiple arguments of the same type. For example, `String.contains` must be called as `String.contains(substr = "foo", "bar")`. - the Flix `List` module offers more than 95 functions. - the Flix `String` module offers more than 95 functions. - the Flix `Foldable` module offers more than 30 functions. - the Flix standard library follows the convention of "subject-last" to enable pipelining (`|>`). ## Ecosystem Did you know that: - Flix has an official Visual Studio Code extension. - Flix has an official dark theme inspired by Monokai called "Flixify Dark". - the Flix website (https://flix.dev/ https://flix.dev/) lists the design principles behind Flix. - Flix has an online playground available at https://play.flix.dev/ https://play.flix.dev/ - Flix has online API documentation available at https://doc.flix.dev/ https://doc.flix.dev/ - the Flix VSCode extension uses the real Flix compiler. - the Flix VSCode extension supports auto-complete, jump to definition, hover to show the type and effect of an expression, find all usages, and more. - the Flix VSCode extension has built-in snippets for type class instances. Try `instance Eq [auto complete]`. - the Flix VSCode extension supports semantic highlighting. - the Flix VSCode extension has built-in "code hints" that suggests when lazy and/or parallel evaluation is enabled or inhibited by impurity. - Flix has community build where Flix libraries can be included in the CI pipeline used to build the Flix compiler. - Flix has a nascent build system and package manager based on GitHub releases. Today it is possible to build, package, and install Flix packages. Dependency management is in the works. ## Compiler Did you know that: - Flix -- by design -- has no compiler warnings, only compiler errors. Warnings can be ignored, but errors cannot be. - the Flix compiler uses monomorphization hence primitive values are (almost) never boxed. - the Flix compiler supports incremental and parallel compilation. - the Flix compiler has more than 28 compiler phases. - the Flix compiler contains more than 80,000 lines of code. - the Flix compiler has more than 13,500 manually written unit tests. - the performance of the Flix compiler is tracked at https://arewefast.flix.dev/ https://arewefast.flix.dev/ ## Other Did you know that: - Flix is developed by programming language researchers at Aarhus University (Denmark) in collaboration with researchers at the University of Waterloo (Canada), and at Eberhard Karls University of Tübingen (Germany), and by a growing open source community. - Several novel aspects of the Flix programming language has been described in the research literature, including its type and effect system and support for first-class Datalog constraints. - Flix is funded by the Independent Research Fund Denmark, Amazon Research, DIREC, the Stibo Foundation, and the Concordium Foundation. - more than 50 people have contributed to the Flix compiler. - more than 2,000 pull requests have been merged into the Flix compiler.
- b0a04gl 1y ago[dead]
- remon 1y agoCurious if anyone can weigh in on why Flix requires a developer to explicitly mark a function as pure. I'd imagine in almost all cases this can be derived through static analysis.
- zambal 1y agoI could be wrong, but the sentence "Flix precisely tracks the purity of every expression in a program." together with some examples of function definitions without the purity/impurity annotation, gave me the impression it's optional, because the compiler can infer it on its own most of the time.
- teamonkey 1y agoI think if you mark a function as pure the compiler guarantees that this is indeed the case.
- mrkeen 1y agoJust like const, private and static.
- anupj 1y ago[dead]
- ZeljkoS 1y agoFlix FAQ (https://flix.dev/faq/ https://flix.dev/faq/) starts normal, but becomes increasingly more hilarious towards the end :D Some gems: --- Q: Wait, division by zero is zero, really? A: Yes. But focusing on this is a bit like focusing on the color of the seats in a spacecraft. --- Q: "This site requires JavaScript" A: People who have criticized the website for using JavaScript: [1], [2], [3], [4], [5]. People who have offered to help refactor the site to use static html: 0. --- Q: I was disappointed to learn that Flix has feature X instead of my favorite feature Y. A: We are deeply sorry to have let you down. --- Q: This is – by far – the worst syntax I have ever seen in a functional language. Semicolons, braces, symbolic soup, et al. It is like if Scala, Java and Haskell had a one night stand in the center of Chernobyl. A: Quite an achievement, wouldn't you say?
- fuzztester 1y agoFlix devs: in the section: What features are not supported by Flix? this Feature on the left side: No Code Before Main does not match the Reason on the right side: In Flix, no code is ever executed before main. Flix has no static initializers (or similar constructs) which are difficult to reason about, error-prone, and often lead to buggy code. you should change the Feature name to: Code Before Main
- FieryTransition 1y agoI'm looking forward to the day where an ml/functional inspired language can be used for real time rendering and game engines, how far are we from that? Realistically, one could argue it's not the right choice overall, but still, it's an application which would push the boundaries of what those languages have been perceived to have the greatness weakness in. An application which is mostly about handing mutable state with high performance.
- achenet 1y agopossibly a stupid answer (and if so, someone please invoke Cunningham's law and correct me) but - Isn't Rust ML/functional inspired? The original compiler was in Ocaml, if I'm not mistaken. Isn't Rust at least somewhat close to being usable for game engines? https://arewegameyet.rs/ https://arewegameyet.rs/
- FieryTransition 1y agoRust is a good candidate, but it lacks some crucial aspects when it comes to what I would consider 'nice to haves' from a modern language in this territory. While rust has traits, borrowing etc, it doesn't have a lot of things with regard to types and optimization. Things like: - A lack of GADTs, or a stronger version, dependent types, or similar type system which would allow one to encode natural relationships, recursive ones, invariants etc. - Tail call optimization guarantees, to allow for mutual recursion and optimization since game engines are just huge state machines, and it would allow to pass functions around which could call each other via mutual recursion, while allowing it to be optimized as well. - Efficient structural sharing of immutable state, which would be memory layout and cache friendly - Built in profiling from the getgo which the language developers would use and refine, so you could get information about how the program behaves over time and space.
- jitl 1y agoRust exists
- mrkeen 1y agoSweet, aside from n/0==0 and no native compilation, it seems like the perfect language!
- jorkadeen 1y agoYou can always add your own `safeDiv` function :-) I believe native compilation is possible via Graal native-image-- but I have not yet tried it.
- remon 1y agoInteresting project but whoever decided "forM" is a good name for a language keyword should be made to gurgle Tabasco sauce for a few minutes.
- jorkadeen 1y agoThat's me. But I must admit that I prefer Cholula Hot Sauce. In addition to the imperative `foreach` construct, Flix has two constructs for applicative[1] and monadic[2] comprehensions: `forA` and `forM`. Since applicatives and monads are related, it is useful that their syntax is similar, since it makes it easy to switch between the two. While having camelCase keywords may seem strange, in this case there is a feeling that it works out well. Certainly, `form` or `fora` would be much worse. Applicative and monadic programming is not a big part of Flix, but it is something we want to support and make ergonomic. Also, these features may have scary names, but the concepts are not too difficult. See [1] and [2] for simple examples of how these features can be used for e.g. error handling. [1] https://doc.flix.dev/applicative-for-yield.html https://doc.flix.dev/applicative-for-yield.html [2] https://doc.flix.dev/monadic-for-yield.html https://doc.flix.dev/monadic-for-yield.html
- bitcrshr 1y agolove the syntax, and excited to mess with it, but man i’m sad to see it’s on the JVM. if i had to guess, a lot of langs like this are on JVM because that’s a lot simpler than writing a whole backend with anywhere near the same performance or reliability, and i totally get that. that being said, bearing in mind that i’m not a Java/JVM developer and only rarely have to use it, for the few nontrivial projects i have shipped with it the build system was by far the most challenging and frustrating. it’s so complex and has such a large surface area. no hate at all, and the trade offs are completely reasonable, but i am hoping during my career we’ll start seeing either a massive simplification of JVM builds or a lot of innovation that would make native compilers easier to build. (as a side note, it is nice to have langs like this for when JVM is the only option)
- lucyjojo 1y agothere's no such thing as generic "jvm builds" as far as i understand though. jvm is the target, it's like saying x64 builds are complex. maybe you re thinking of ant or maven or gradle? there are plenty others. you can build basic java with "javac myfile.java". done. each jvm language has its own build tools and some build tools cover jvm languages in between others.
- bitcrshr 1y agoi think you’re right, though i think i was thinking about about this at a higher level. i more meant that the languages in the JVM ecosystem I have experience with (java, kotlin, and scala) have all given me similar unpleasant experiences building them. same tools too, though you probably wouldn’t use sbt for non-scala projects even though you could. the main pain points for me are dependencies, packaging, and configuration. best i can tell, those pains are shared between anything that targets JVM, especially those that want to have good interop.
- throwthrow0987 1y agoIf you have an effect ReadsFromDB, you can't enforce statically that someone will not come along and change the ReadsFromDB effect to write to the db. That's why I think Haskell got it right in the first instance, functions are either pure or IO.
- jorkadeen 1y agoWhat do you mean? In Flix, if a function has "Bool" as a return type then it can only return a Boolean value. That's what a type system ensures. Similarly, in Flix if a function has the "ReadsFromDB" effect then it can call operations that cause "ReadsFromDB"-- but it cannot cause any other effect. In particular, if there is also a "WriteToDb" then it cannot perform that effect. This is not just aspirational. It is an iron-clad guarantee; it is what is formally called "effect safety" and it has been proven for calculi that model the Flix type and effect system. To sum up: In Flix: - If a function is pure then it cannot perform side-effects. - If a function has the Console effect then it can only perform operations defined on Console. - If a function has the Console and Http effect then it can only perform operations defined on Console and Http. and so on.
- thdhhghgbhy 1y agoBut you have user defined effects don't you? E.g say I define an effect ReadsFromDB, it doesn't necessarily do what it says on the tin, and there is no way a compiler can check that it does. It could read from the db, and send some rockets into space. So a consequence of that is that these "effect systems" just amount to giving names to blocks of code. That's not necessarily a bad thing.
- xigoi 1y agoIf you define a variable called number_of_apples, there is no way for the compiler to check that it actually contains the number of apples. How is that different?
- thdhhghgbhy 1y ago
- deryilz 1y agoI'm quite liking the syntax, especially the !> operator.
- angra_mainyu 1y agoIt looks beautiful! Now, if I could just find a non-JVM version...
- rixed 1y ago"Flix also features full tail call elimination which has some run-time performance cost." What are the run time costs being refered to here?
- jorkadeen 1y agoIn the uncommon case, some stack frames must be heap allocated. This is unavoidable when (a) the runtime enviroment, here the JVM, does not support tail calls, and (b) the language wants to guarantee that _any_[1] tail call does not grow the stack. [1] Any call. Not just a call to the same function.
- yencabulator 1y agoThe first example[1] has a classic look-before-you-leap stupidity. That's not a great look! match File.exists(f) { ... match File.stat(f) { The file can be removed after the first call, before the second. Just call stat and handle ENOENT correctly. [1]: The page seems to randomize which one is shown. I got the "File information" one in the dropdown.
- iwinux 1y agoI don't care how powerful your language is. PLEASE STOPPING USING THE \ CHARACTER FOR ANYTHING OTHER THAN ESCAPING!!!!
- russism 1y ago\