16 ms·
Grain: A strongly-typed functional programming language for the modern web
- crimsonalucard 8y agoanybody try it?
- willtim 8y agoTo have a JavaScript feel with type inference, which I assume they are aiming for given the syntax, I would like to see extensible records (structural typing), which remove the need to declare nominal record types. Purescript and Elm both have this feature.
- devxpy 8y agoDart anybody?
- redsolver 8y agoDart is amazing
- continuational 8y agoYes, Dart is amazingly broken for a modern language. This compiles: List<Animal> animals = [Dog()]; List<Cat> cats = animals; What is a static type system worth if it doesn't catch type errors at compile time?
- fcurts 8y agoDart 2 has a sound type system and catches this at compile time.
- cmmartin 8y agoGrain is quite different. Grain is more functional (no classes or context, tuples). Dart compiles to Javascript. Grain compiles to web assembly. Dart requires you to define types. Grain provides type safety and zero runtime errors without ever defining types manually.
- pmontra 8y agoThe documentation about types says to look at the Readme of the compiler, which is very short and doesn't tell anything about types. Same thing for many other entries in the side menu. The examples don't have any type declaration. So, type inference and no reuse of the same variable with a different type, even when forcing mutation? Unfortunately the documentation is still too skinny. A note to language designers: I can understand the { } but if you use them why do you also need the ( ) around the conditionals here? if (n <= 1) { n == 0 } else { isOdd(n - 1) } The parser can find where the condition starts (after the if) and ends (at the {) and we won't have to type two useless characters. It's ergonomics.
- andyonthewings 8y ago( ) are only optional if { } are mandatory, which is not true for some languages. e.g. in Haxe, one can write static function isEven(n) return if (n <= 1) n == 0; else isOdd(n - 1); static function isOdd(n) return if (n <= 1) n == 1; else isEven(n - 1); i.e. An if expression consists of other expressions that may or may not be a block expression ({ }).
- pmontra 8y agoThere is a great deal of variability in languages about that. Python ends if lines with a : which might help the parser, but maybe not because it was a late addition to help readability. For me it adds work when moving code around because I have to add or remove the : Ruby does totally without any terminator in that context (in other contexts it has its own {} or do...end). The parser keeps processing successive lines until it understands that what follows can't belong to the conditional. I prefer that approach because it's the language/compiler that has to help me, not the other way around.
- deleted 8y ago[deleted]
- 8y ago
- paradite 8y agoHow does the example in Functions section show that function is first class citizen? It is merely calling a function within another function. I would expect the second function to take in first function as a parameter (which JavaScript already has).
- Tehnix 8y agoI was hoping for currying, but was disappointed when all the functions were fully applied. It don’t really see either, how this tells anything about first-class functions :/
- tlrobinson 8y agoThe main page doesn't do a great job of showing what's interesting about Grain vs. JavaScript. The only hint is this: "No runtime exceptions, ever. Every bit of Grain you write is thoroughly sifted for type errors, with no need for any type annotations." Maybe show some examples of errors Grain would catch that JavaScript wouldn't, like Elm does: http://elm-lang.org/ http://elm-lang.org/
- thangngoc89 8y agoI think the marketing page is not doing a great job. Grain is a language compiled to WebAssembly. So comparing it with either Javascript or Elm is pointless
- tlrobinson 8y ago> So comparing it with either Javascript or Elm is pointless Why? They all target browsers. What else would you compare it to?
- thangngoc89 8y agoLike comparing to Rust compilation to WebAssembly for example?
- ForHackernews 8y agoDoes Rust have any DOM integration?
- ekidd 8y agoYes. For a while, you've been able to embed JavaScript wrappers using stdweb (https://github.com/koute/stdweb https://github.com/koute/stdweb). There are pre-built libraries covering much of the DOM. But you may need to submit PRs if you get heavily into <video> or something else with non-standard APIs. The shiny new toy is wasm-bindgen (https://github.com/rustwasm/wasm-bindgen https://github.com/rustwasm/wasm-bindgen), which will soon allow the use of WebIDL (https://heycam.github.io/webidl/ https://heycam.github.io/webidl/) to wrap the entire browser API, if I understand correctly. In practice, it all seems to work pretty well. But for public-facing sites, you need to watch the number of dependencies you include and keep the *.wasm size down.
- thangngoc89 8y agoModerators: The title should have the WebAssembly in it to avoid confusion. This is not yet another language that compiles to Javascript.
- anonytrary 8y agoI mean, this looks interesting, but why was this posted prematurely? Now I have to remember to look this up again in two months when they actually have a website that isn't 3% done. Basically all of the docs are in the "todo" stage. I always get a bit annoyed when people post their pages way too early.
- mirekrusin 8y agoMaybe they prefer to focus on writing actual language than PR’ish stuff? It’s quite refreshing after seeing too much of the opposite (especially in blockchain space where you have in 99% of cases just pretty PR page and zero product/code). I’m sure they’re open and would be happy to see contributions. Translating source code into docs is a great way to learn and it looks like very pleasant language to read.
- kachnuv_ocasek 8y agoDocumentation can hardly be called "PR'ish stuff". It is also (ideally) far from some kind of "translation" of code into natural language.
- jholman 8y agoWhat makes you think that the HN poster has any affiliation with the project, or vice versa?
- rkangel 8y ago"If you are not embarrassed by the first version of your product, you've launched too late." -Reid Hoffman In this case, publicising, and getting more contributors can help fix these problems.
- alkonaut 8y agoHow does this compare to Elm and F# (Fable)?
- LolNoGenerics 8y agoIs the language incomplete like the docs?
- millstone 8y agoWhat is meant by "zero runtime errors?" An example of a "runtime error" is the head of an empty list; how does Grain handle this?
- frou_dh 8y agoPresumably the head function returns a value of type Optional/Maybe, that needs to be pattern matched against statically.
- masklinn 8y agoGrain seems way unfinished and the stdlib does not seem to have any such function[0], so here's how Elm handles it instead as it has the same target/ethos of avoiding runtime errors: http://package.elm-lang.org/packages/elm-lang/core/latest/List#head http://package.elm-lang.org/packages/elm-lang/core/latest/Li... [0] it's not very useful either if you have pattern matching on lists, you can just match the list directly.
- marijn 8y agoThe DOM example further down the page, which does no result checking on queries that can absolutely fail to find an element, makes me very skeptical of this claim.
- zumu 8y agoWhy not just compile OCaml to wasm? Why another language?
- tom_mellior 8y agoPoking around in the sources, it looks like this is the OCaml compiler, with the frontend apparently tweaked to accept the new syntax. But this is not mentioned anywhere that I can see. The "Copyright copyright 2017-2018 Philip Blair and Oscar Spencer." line in the README is highly misleading in this context, since most of the actual source files are marked with OCaml's copyright header.
- afrisch 8y agoMany files are taken from the OCaml compiler and then adapted, but changes seems a bit deeper than just a different syntax. It would indeed seem fair for the authors to at least make it clear in the toplevel README that the front-end (parsetree representation and type-checking) is indeed / started as a fork of the OCaml code base. Considering ongoing efforts to create a WebAssembly backend for OCaml (and thus Reason), I wonder what would be the selling point of Grain.
- ubertaco 8y agoEven syntactically, this looks a lot like if you took ReasonML, disallowed type annotations, did away with its ecosystem, and compiled to WebAssembly. Aside from the wasm compilation, I don't see why this exists.
- senorsmile 8y agoThat was my question only having recently started looking into ReasonML seriously. Sounds like I'll just stick to Reason!
- tom_mellior 8y ago> Many files are taken from the OCaml compiler and then adapted [...] I went back and checked, and Grain not only takes OCaml's code without clear attribution but redistributes that code under GPLv3 where the original code is under LGPLv2.1. That's bad.
- tom_mellior 8y agoHas anyone found in the sources if/how they treat garbage collection?
- vilu 8y agoNo, I would be interested in that too. I don't know anything about Web Assembly but maybe GC is handled by Web Assembly?
- masklinn 8y agoThere are plans to eventually integrate GC into wasm, but at the moment the GC has to be implemented and bundled in the wasm file. That is in fact one of Rust's advantages there. And of course wasm supporting a GC does not mean languages targeting wasm will want to use it (and lose the flexibility of providing their own).
- pitb0ss 8y agoYes. They currently use reference counting since WASM doesn't allow stack inspection.
- tom_mellior 8y agoDo you have a link to the source?
- truncate 8y agoHow does do handle memory management? If I'm not mistaken, in webassembly programs use a fixed buffer to access memory, which means you need some runtime support to manage that, or apply some kind of technique like this[1]. [1] http://home.pipeline.com/~hbaker1/CheneyMTA.html http://home.pipeline.com/~hbaker1/CheneyMTA.html
- munificent 8y agoIt appears to allocate memory but never free it: https://github.com/grain-lang/grain/blob/master/runtime/src/core/heap.js https://github.com/grain-lang/grain/blob/master/runtime/src/... A lot of new languages start out this way, where they just assume memory is infinite and then eventually add the GC later. That's a really nasty ball of technical debt to be sitting on, and I've seen nascent language implementations die because they couldn't get past it.
- knocte 8y agoDoesn't encourage immutability because variables are not readonly by default. I would advice the language designers to require the "mutable" keyword for variables than can be re-assigned. (Similar to F# approach.)
- tom_mellior 8y agoI think you're mistaken. It seems to me that you need to create an explicit "box" (a reference) to make things mutable.
- pjmlp 8y agoML approach.
- Tade0 8y agoI have a distrust for languages that advertise themselves as "strongly-typed" or "bringing sanity to the front-end" - the former doesn't have a single clear definition and the latter - while not the case here - is questionable in it's own right.
- ealhad 8y agoMoreover, they don't really show anything to make their point — I can't see any type annotations on the frontpage.
- HindleyMilnerTI 8y ago> it's 2018 > type annotations https://en.wikipedia.org/wiki/Type_inference https://en.wikipedia.org/wiki/Type_inference
- leshow 8y agoType annotations can be helpful in writing maximally polymorphic code and in self documentation, independent of type inference. When I write Haskell, I still annotate my code.
- always_good 8y agoAlso, throwing out all type annotations makes code pretty hard to read, especially outside your IDE like in a Github repo. Taken to an extreme, it feels like reading a dynamically-typed language where you have to keep the various variable types in your head when debugging. There's a middle ground.
- always_good 8y agoPretty lazy comment. There's a reason you still at least annotate the top level in Haskell, Elm, and friends even though the compiler could've inferred it. It's because humans have to read it.
- junke 8y agoisOdd and isEven don't work with negative numbers.
- slifin 8y agoThis looks nice, but it does need more documentation and an online playground/eco system which understandably should come in time
- rkangel 8y agoWhy do all new languages aimed at the browser seem to be "strongly typed, functional". I have no objection whatsoever, but we've seen Elm, Purescript and now this. Or is my perception skewed by the "HN Echo Chamber"?
- Latty 8y agoI think it's just that JS caters to those features the least, so that's where you see new languages from people that want them.
- bad_user 8y ago"Strong typing" as a term has actually been muddied and doesn't mean much nowadays other than "not C", being re-purposed for marketing reasons. Irregardless of the language, you don't want your language to be weakly typed, although in fact you can say that about most dynamically typed languages. Leaving the marketing efforts aside, what people want to express is "statically typed". A static type system can prove a lot of things about your program. Traditionally you could rely on (good) static type system to prove that your program is memory safe, or that it has as few runtime errors as possible, preferably zero. N.B. don't fall into the trap of saying that a language like C is statically typed. When you can pass void pointers around and cast that to anything, that's in fact not static typing. Type theory has a lot to do with math logic actually, the two being highly interchangeable. Statically typed compilers can prove various properties about your program, freeing the developer from writing certain classes of tests, plus it makes refactoring easier. Refactoring, correctness, these are things people have always struggled with in JavaScript, especially due to JavaScript's nature. Quick, can you tell me the answer to "Math.min() < Math.max()" in JavaScript? You know it's a trick question, given this is JavaScript, don't you ;-) --- Other than ClojureScript, I don't know of any other dynamic language targeting JavaScript engines and that's interesting. None. And ClojureScript is only interesting because it is a LISP and because it has sane conventions and defaults. Languages providing superficial syntactic sugar, such as CoffeeScript, have been a really bad idea and I'm glad that we've moved on. Therefore the innovation that happens tends to happen in statically typed languages, because there's a lot there left to explore and because such languages tend to bring value. That said I always wonder what new languages bring to the table versus already available alternatives like PureScript, Scala.js, ClojureScript, Elm, etc. And from the TFA I don't understand what those advantages are.
- bandrami 8y agoWhat's the incentive people have to combine type systems with functional programming? At least in broad strokes I think of typing and immutability (which is the goal of functional-style programming) as solving the same problem in two different ways. If you write control flow that returns values which are immutably bound lexically, what is the point of a type system?
- adwn 8y agoImmutability gives guarantees at runtime, a type system gives guarantees at compile time. Or, from a different perspective, immutability guarantees a certain property – the value – of an item, while a type system guarantees different properties for all items of a type. Those two concerns are mostly orthogonal to each other.
- yetkin 8y agoThis is just a prototypal IDEA right? motivation? benchmark? demo? build system?
- nine_k 8y agoSince it's pretty ML-flavored, a comparison with Reason [1] would be nice. I see compiling to WASM as the key differentiator now. This likely means that all the mechanics required for an ML-style language, like garbage collection, must be included in a runtime library. [1]: https://reasonml.github.io/ https://reasonml.github.io/
- wffurr 8y agoOnly until the WebAssembly spec included access to the host GC: >>> there's already a very efficient, solidly tested, constantly improving garbage collector in your browser that uses all the possible dirty low-level tricks known to mankind, which is the GC being used for JavaScript. What if we could give you access to the garbage collector directly? https://blog.benj.me/2018/07/04/mozilla-2018-faster-calls-and-anyref/ https://blog.benj.me/2018/07/04/mozilla-2018-faster-calls-an...
- nine_k 8y agoIsn't it still pretty experimental?
- vanderZwan 8y agoWell, Grain is as well so is that really an issue?
- spinningslate 8y agoI'd hope this is indicative of wasm precipitating a wave of creativity. From a purely technical point of view I actually don't care. Elm is fast, complete, elegant and has perhaps the most user-friendly compiler on the planet. The fact it happens to target js and not wasm (at this point) is practically irrelevant. I can see, though, that wasm might encourage experimentation by a wider group of people who are put off by targetting js. Coming back to Elm, it'd be great to see others consider the wider architectural questions. The Elm architecture and language are beautifully complementary. That's stark when looking at react - which was copied from (or at least inspired by) the Elm architecture. However, being js-based, it doesn't have the mutual consistency of elm - and so has to resort to syntactic gymnastics. Anyway, that's getting off topic. Grain is clearly early stage. Anyone motivated enough to conceive and deliver a language deserves some encouragement. Will be interesting to see how it evolves.
- tylerhou 8y agoHow does Grain prevent bottom with static type checking? Totality is undecidable in Turing complete languages, so “no runtime errors” is probably false (maybe they “solved” the halting problem?).
- kowdermeister 8y agoA functional language with readable syntax for mere mortals? Sign me up :)
- fgheorghe 8y agoPretty useless. This yet another js based language.
- rzwitserloot 8y agoPretty much the first sentence on the page: > No runtime exceptions, ever. Every bit of Grain you write is thoroughly sifted for type errors, with no need for any type annotations. That's... weird to me. That seems to posit that ALL runtime exceptions are necessarily type errors. Huh? What about full disk, DB errors, data verification error, parsing errors, network errors, and tons of other errors that don't appear to be type system related? [A] This language only doesn't realize this class of errors exist, which, um, seriously? That can't bode well. [B] The language uses the type system to propagate such errors. `Either<Result, ErrorCode>` for example. The language is somewhat unique in that it is designed to enforce such code style for ALL possible error conditions. [C] The language returns null or blank objects on error conditions, such as how (early) javascript returns 'NaN' when trying to parse "hello!" as a number, instead of raising an error condition. That's a style choice I really wouldn't like, but I guess to each their own.
- leshow 8y agoThe likely reason is B. Elm is a frontend web language that also has this guarantee, and it uses Either types for situations that can fail. It's not entirely unique in that regard, there are other languages (mostly) without exceptions; Rust, for example.
- mml 8y agoElm goes even further, insisting that you actually handle the Error types in some way.
- colanderman 8y agoI would assume case B, which isn't really that unique. Erlang for example follows that pattern (and has no concept of "exception"). After all, I/O errors, parsing errors, etc., aren't exceptional; they very much should be expected. Forcing them to be handled in the normal code path helps create robust systems. (There are of course also true runtime errors -- e.g. out-of-memory -- and precondition errors -- i.e., coding errors that fall outside the capability of the type system to enforce -- which do not fit this pattern.)
- alexeiz 8y agoHow does Grain compare with the Reason language from Facebook which is also based on OCaml?
- yosefzeev 8y agoArch installs some version of dune-project the make command does not recognize. Not in the mood to edit a package build just to try this programming language out.
- piinbinary 8y agoIf it's not too late to change, might I suggest doing away with the 'let rec ... and ...' syntax? The way to group mutually recursive bindings can be determined by finding the strongly connected components of the graph of the references between functions, so users don't need to manually specify it.
- junke 8y agoBut then how do you shadow previous bindings? let f x = if (x == 0) then 0 else (f x)
- piinbinary 8y agoPotentially controversial opinion: shadowing bindings is a bad idea.
- zumu 8y agoI do like the explicitness of marking recursive functions with 'rec', however. What would the syntax look like if it was no longer required?
- c-smile 8y agoIMO modern web language should have some notion of events as in my Sciter ( https://sciter.com/event-handling/ https://sciter.com/event-handling/ ) for example: event click $(table > thead > tr > th) { // click on table header cell // 'this' is that th element } class Widget : Element { function attached() {...} event click $(span.up) { this.increment(); } event click $(span.down) { this.decrement(); } event mousedown { this.state.focus = true; } ... }
- joehewitt 8y agoYES. Every time I see a new language come out without first class event support it is obvious the creator never wrote a lick of front end code in their life.
- mkl 8y agoCan you explain how these differ from ordinary callback functions? I haven't done any web development to speak of, but I've done a fair bit of GUI stuff, doing things like this snippet appears to in languages that don't have "events" as a separate category of thing.
- c-smile 8y agoThis observable.on("click", observerFunc); // or observable.addEventListener(...); is an executable statement. And this class Widget : Element { event click { … observer's code … } } is a declaration. That executable statement needs to be called at some point of time. So the observable can be in two states - with and without that event handler. While class declaration is an invariant (at least in Sciter) - as soon as element is in DOM it has that class and consistent set of event handlers in place. Such binding is done by, again, CSS declaration: widget { prototype: Widget url(path); // <widget> controller display: block; ... } "I've done a fair bit of GUI stuff" AFAIR VB6 and Delphi allow to declare event handlers without explicit/runtime binding - that's close as a concept to the above.
- sbjs 8y agoThe "DOM Interaction" and "DOM Manipulation" sections just show imperative code. So how is this a fundamental improvement over using jQuery? Especially for a language that markets itself as "seriously functional", it feels like a big step backward. I can't see what benefit this actually brings except being easier for OCaml developers to write web apps with. And even then they'd probably have no trouble learning TypeScript which doesn't need a bridge since it's a strict superset of JS.