[HN Gopher] Programming a space invader in OCaml and OpenGL: les...
       ___________________________________________________________________
        
       Programming a space invader in OCaml and OpenGL: lessons learned
        
       Author : juliendemangeon
       Score  : 90 points
       Date   : 2020-02-21 14:02 UTC (8 hours ago)
        
 (HTM) web link (marmelab.com)
 (TXT) w3m dump (marmelab.com)
        
       | cpursley wrote:
       | Marmelab makes the pretty awesome react-admin library for
       | autogenerating admin interfaces:
       | 
       | https://github.com/marmelab/react-admin
       | 
       | I'd love to see an official Marmelab adapter so I can build my
       | admin interfaces with ReasonML.
        
         | Kmaschta wrote:
         | We already have hard time migrating it to TypeScript :p How
         | such an adapter might work?
        
       | adamnemecek wrote:
       | Between reasonml and elm which one should I pick?
        
         | weavie wrote:
         | If you've not used an ML before, start with Elm.
         | 
         | Once you feel you have that sussed - it shouldn't take too long
         | - pull up ReasonML and give it a go. Use the Bucklscript-Tea
         | library - the architecture will be familiar from Elm.
         | 
         | Then give Reason-React a go.
         | 
         | Once that itch has been scratched move on to PureScript for a
         | whole new rabbit hole to fall down.
        
           | adamnemecek wrote:
           | I mean I'm familiar with ml and haskell, I'm more interested
           | in what's the best platform for building things. The language
           | itself is only a part of the equation.
        
             | azangru wrote:
             | I believe Reason is more practical (easier FFI), but as for
             | building things, at this point it's probably Typescript :-)
             | 
             | Reason still hasn't had its async story ironed out, and has
             | poor support for Unicode[0]
             | 
             | [0] "ReasonML strings are encoded as UTF-8 and not
             | compatible with JavaScript's UTF-16 strings" (from
             | https://2ality.com/2017/12/basic-types-reasonml.html)
        
         | azangru wrote:
         | Does Purescript also come into the equation? :-)
        
       | SkySkimmer wrote:
       | >Even though it is known for its robustness and its large
       | standard library
       | 
       | I thought the ocaml stdlib was relatively small though?
        
       | rwmj wrote:
       | dnf install ocaml ocaml-lablgl-devel
       | 
       | ?
       | 
       | Anyway here's a toy game I wrote in GL + ODE + OCaml years ago:
       | https://github.com/fccm/OCamlODE/blob/master/examples/katama...
        
       | vzaliva wrote:
       | This article title and conclusions are misleading. It shows how
       | to write a simple game in OCaml and then proceeds to conclude
       | that ReasonML is better. I would expect the author to have the
       | same game implemented in ReasonML for comparison to show us why.
       | Otherwise, it is not very convincing.
        
         | gameswithgo wrote:
         | having done some OCaml and F#, where F#'s syntax is more like
         | reason, i think it is pretty clear that OCaml is a fascinating
         | language but what does impose some weird syntactic work that
         | both reason and f# relieve you of. probably to someone
         | sufficiently used to ocaml it doesn't matter but it can hurt
         | adoption
        
           | sdegutis wrote:
           | I always thought ReasonML was just a more JavaScript-ish
           | syntax on top of OCaml, not necessarily better but just
           | different. In what ways is it an actual _improvement_?
        
           | nv-vn wrote:
           | I don't see how you can say F#'s syntax is more like Reason.
           | OCaml and F# have nearly identical syntax for the core
           | language, with the few differences being:
           | 
           | 1) places features diverged
           | 
           | 2) modules
           | 
           | 3) F#'s "light" syntax mode
           | 
           | None of these really seem like Reason at all. Do you have any
           | specific places where they're similar?
        
         | dang wrote:
         | We've changed the title to that of the article, as the site
         | guidelines ask
         | (https://news.ycombinator.com/newsguidelines.html).
         | 
         | Submitted title was "Is ReasonML good by itself or the
         | underlying OCaml the source of awesomeness?"
        
       | alharith wrote:
       | I am confused by this article. It went an entirely different
       | direction based on the question proposed. It was all
       | entertaining, nonetheless, but besides some passing comments to
       | Reason's documentation being better, the question does not seem
       | to be explored much by this article. It's a good article and
       | should be renamed to maybe "Getting started with OCaml and
       | OpenGL"
        
         | juliendemangeon wrote:
         | You're absolutely right. I wanted to justify my exploration by
         | way of comparison between ReasonML and Ocaml.
         | 
         | The title ("Programming A Space Invader In OCaml and OpenGL:
         | Lessons Learned") still fits with the content, don't you think?
        
           | alharith wrote:
           | I see that now, yes I do. I think maybe the headings and
           | subheadings are also throwing me off as well. I wasn't sure
           | if I was reading one of those types of blogs that have a
           | continuous feed of articles on one page.
        
       | pjmlp wrote:
       | The underlying OCaml naturally.
       | 
       | Having learned ML via Objective Caml's predecessor, Caml Light,
       | ReasonML seems to be just sugar coating for those with aversion
       | to ML classical syntax.
        
         | hellofunk wrote:
         | > ReasonML seems to be just sugar coating
         | 
         | That's exactly what it is, no secret about that, that's the
         | goal of that project.
        
           | pjmlp wrote:
           | Which begs the question why not learn the real deal, instead
           | of adding another layer to debug.
           | 
           | Programing isn't poetry.
        
             | mhd wrote:
             | > Programing isn't poetry.
             | 
             | First time I've heard a C-like syntax described as
             | "poetic".
        
             | sshine wrote:
             | You could say the same thing about Erlang and Elixir.
             | 
             | Or Java and Kotlin / Scala.
             | 
             | Depending on how well an alternative syntax is requested
             | and adopted by the existing ecosystem surrounding the
             | particular VM, YMMV. Without knowing, I think you get quite
             | different answers in each case.
        
               | pjmlp wrote:
               | I not only could, I say so.
               | 
               | Focus on platform languages and you always win long term.
        
             | k__ wrote:
             | True.
             | 
             | But the accumulation of @-signs, for example, seems to be a
             | bit much.
        
             | msla wrote:
             | Programming is expressing programmer intent to the greatest
             | extent possible given technological constraints. Sometimes,
             | that's moving from machine code to assembly language[1];
             | sometimes, that's building a declarative language to
             | express some specific logic. Finding new ways to preserve
             | programmer intent in machine-checkable ways (that is, not
             | just by adding comments) is one of the consistent goals of
             | programming language design.
             | 
             | [1] Yes, humans used to write machine code. By hand.
             | Computers were for serious work, not mere clerical tasks
             | such as translating mnemonic order codes to binary and
             | doing address arithmetic.
        
             | pcwalton wrote:
             | Because people who know other programming languages, but
             | not ML, might want to read your code, and it's nice if it
             | looks familiar to them.
        
               | pjmlp wrote:
               | That is how languages like Go get designed, pour souls
               | not able to spend some time learning.
        
               | pcwalton wrote:
               | I _wish_ Go had been a reskin of OCaml.
        
             | dean177 wrote:
             | There is no layer above, it's not like coffeescript which
             | compiles to another language. It's literally an alternative
             | syntax.
        
               | pjmlp wrote:
               | Sure it does, unless there is a ReasonML native compiler
               | with its own ecosystem now.
        
             | throwaway894345 wrote:
             | If it works properly there isn't another layer to debug
             | (and anyway, one has to debug OCaml's syntax as it is, so
             | it's more like trading one debug layer for another). I've
             | never had to debug into assembly before, for example. And
             | while syntax is normally just superficial, OCaml goes out
             | of its way to be obscure and I don't have time for that.
             | Especially with all of its other warts (stdlib issues,
             | crappy package management, crappy build tooling, still no
             | multithreading, etc). I eventually just gave up. Which is
             | too bad because the type system (absent the OO stuff) could
             | be useful.
        
               | [deleted]
        
             | jherdman wrote:
             | Because sometimes the layer on top can express ideas more
             | succinctly. A classic example is CoffeeScript's fat arrow
             | syntax. It expressed a pattern in JavaScript we didn't, at
             | the time, have a shorthand for. Example:
             | https://coffeescript.org/#fat-arrow
        
               | pjmlp wrote:
               | And now it is dead, leaving behind a pile of code to
               | rewrite in next cool toy.
        
               | no_wizard wrote:
               | Does Not look dead to me. last activity is within the
               | last 30 days or so.
               | 
               | https://github.com/jashkenas/coffeescript/
               | 
               | Its not as _popular_ to be certain, though.
        
               | pjmlp wrote:
               | I bet Fortran and Cobol are getting more jobs offers than
               | CoffeeScript.
        
               | blunte wrote:
               | Whereby you seem to be making the case for "dead"
               | languages.
        
               | throwaway894345 wrote:
               | In fairness, it's dead because it was shitty and made
               | most things harder, and the things it did improve JS
               | copied. If OCaml fixes its syntax, then we won't have any
               | need for Reason.
        
               | pjmlp wrote:
               | There isn't anything to fix.
        
               | throwaway894345 wrote:
               | If you were right OCaml wouldn't be the only language
               | with a popular syntax veneer.
        
               | erichocean wrote:
               | TypeScript says hi.
        
               | throwaway894345 wrote:
               | TypeScript extends the syntax to support type
               | annotations; it's not trying to fundamentally fix JS
               | syntax.
        
               | erichocean wrote:
               | Now "static typing" _isn 't_ a fundamental part of a
               | language?                   -\_(tsu)_/-
        
               | staticassertion wrote:
               | Typescript makes virtually no changes to JS syntax,
               | except what's necessary to support types.
        
               | erichocean wrote:
               | TypeScript classes, constructors and enums say hi.
               | 
               | Talk about moving the goalposts...
        
               | throwaway894345 wrote:
               | No one is moving the goalposts. TypeScript's raison
               | d'etre is to add static typing to JS. Reason's is to fix
               | the syntax.
               | 
               | (Yes, TS adds new grammatical constructs, but grammatical
               | constructs are about grammar, not syntax, contra Reason).
        
               | pdimitar wrote:
               | As a guy who tried to get into OCaml development several
               | times, the language is not the problem at all. It's the
               | several different "standard" libraries, lack of good
               | official agreed upon tutorials and guides, and the fact
               | that it has a GIL and is essentially single-threaded.
               | 
               | If OCaml had Erlang's runtime (parallelism and
               | concurrency via actors with message inboxes) it would
               | likely be the most used language.
               | 
               | Its lack of adoption isn't at all related to syntax IMO.
               | Programmers use all sorts of quirky syntaxes and the
               | world hasn't ended yet.
        
               | throwaway894345 wrote:
               | > As a guy who tried to get into OCaml development
               | several times, the language is not the problem at all.
               | It's the several different "standard" libraries, lack of
               | good official agreed upon tutorials and guides, and the
               | fact that it has a GIL and is essentially single-
               | threaded.
               | 
               | I agree that those things are pain points (I said as much
               | upthread), but clearly the language is also part of the
               | problem or else there would be no interest in Reason.
               | 
               | > As a guy who tried to get into OCaml development
               | several times, the language is not the problem at all.
               | It's the several different "standard" libraries, lack of
               | good official agreed upon tutorials and guides, and the
               | fact that it has a GIL and is essentially single-
               | threaded.
               | 
               | A big reason Erlang is similarly unpopular is its syntax
               | as well (many of the most popular languages are
               | dynamically typed, so we know it's not the type system).
               | This theory is supported by the relative popularity of
               | Elixir, which shares Erlang's runtime and which has
               | enjoyed a fair amount of popularity in a relatively short
               | time despite introducing a number of syntax- and non-
               | syntax-related quirks. OCaml on BEAM would certainly
               | appeal to the intersection of FP and static-typing
               | enthusiasts, but it would not remotely be popular.
        
               | pdimitar wrote:
               | > _OCaml on BEAM would certainly appeal to the
               | intersection of FP and static-typing enthusiasts, but it
               | would not remotely be popular._
               | 
               | I realise what I said is not an undisputable truth and I
               | wouldn't argue about it. I probably should have just said
               | that I am observing an almost global strive for dev teams
               | to be able to catch bugs earlier and to have a bit more
               | guarantees by the mere virtue of the program successfully
               | compiling. But it might be my filter bubble.
               | 
               | This is why I said an OCaml with the BEAM guarantees
               | would likely rise very high; because my observations lead
               | me to the belief that people want more compile-time
               | guarantees. And yeah, that might be a skewed observation.
        
               | throwaway894345 wrote:
               | > I realise what I said is not an undisputable truth and
               | I wouldn't argue about it. I probably should have just
               | said that I am observing an almost global strive for dev
               | teams to be able to catch bugs earlier and to have a bit
               | more guarantees by the mere virtue of the program
               | successfully compiling. But it might be my filter bubble.
               | 
               | I think this is a pretty broad pattern, but:
               | 
               | 1. It's not happening in isolation; there's also a move
               | toward greater development velocity
               | 
               | 2. There's lots of low-hanging fruit to be had--lots of
               | people can get tremendous safety benefits by moving from
               | languages like JS and Python to Go or TypeScript or
               | typed-Python even if they don't have as elegant a type
               | system as OCaml (and those alternatives don't require the
               | same tradeoffs as OCaml or even an OCaml on BEAM).
               | 
               | > This is why I said an OCaml with the BEAM guarantees
               | would likely rise very high; because my observations lead
               | me to the belief that people want more compile-time
               | guarantees. And yeah, that might be a skewed observation.
               | 
               | Like I said, I don't think it's a skewed observation,
               | it's just that there are other ways of getting most of
               | those compile-time safety benefits with fewer tradeoffs.
               | But I would be a huge fanboy of an OCaml-like type system
               | on BEAM (especially if it can have Go- or Rust-like
               | attentiveness to practical software engineering
               | concerns).
        
               | WorldMaker wrote:
               | On the other hand, if Reason were such a massive
               | improvement to OCaml syntax, where are the people
               | clamoring for F# to adopt more of Reason's ideas?
               | 
               | (Admittedly, F# already shares a couple Reason ideas like
               | C-style comments instead of OCaml's traditional ones. So
               | the waters are clearly muddy here to begin with, but a
               | lot of the big things like let-binding scopes and ;;
               | versus ; presumably would be big F# requests if Reason
               | was so strongly superior to the inherited OCaml legacy.)
        
               | throwaway894345 wrote:
               | > where are the people clamoring for F# to adopt more of
               | Reason's ideas?
               | 
               | Probably writing C#.
        
             | zem wrote:
             | reason isn't another layer, it's an alternate syntax. it
             | doesn't compile via translation to ocaml code; both reason
             | syntax and ocaml syntax compile to the same thing.
        
             | toolz wrote:
             | I disagree, code is for and by humans. There are likely
             | very real runtime consequences to having code that is
             | "ugly", because the next human to touch it will value it
             | less and do a suboptimal job.
             | 
             | Of course all of this is highly subjective, but my
             | understanding is that it's important to consider if you
             | want highly successful projects.
        
               | wbl wrote:
               | ML syntax is fine.
        
               | Gene_Parmesan wrote:
               | > code is for and by humans
               | 
               | I think this is very much domain dependent. Generally the
               | more important efficiency is, the less I find this to be
               | true. And really, code is always for the machine at the
               | end of the day.
               | 
               | Additionally, if an added code layer makes the code more
               | difficult to debug, that's also making the code worse for
               | humans. Note I'm not arguing for or against whether
               | that's happening in the case of OCaml/ReasonML, just
               | making the point.
        
               | sshine wrote:
               | > code is always for the machine at the end of the day
               | 
               | On the other hand, code is read much more than it is
               | written.
               | 
               | You may also regard efficiency as a necessary evil if the
               | cost is readability.
               | 
               | Ultimately the winning strategy in this regard is
               | achieving "free abstraction", making code that is both
               | readable and efficient. Different languages aim at this.
               | C++ has been best at this for most of history. Haskell
               | and Rust are competing at this now as well.
               | 
               | OCaml isn't exactly efficient because of free
               | abstraction, but because of its extremely simple
               | translation strategies. OCaml's "flambda" compiler
               | extension wasn't released as stable until 4.03 (2016),
               | which means that before that, very little high-level
               | transformation was happening.
               | 
               | My experience is that OCaml programmers care about low-
               | level optimization, for good and for bad.
               | 
               | For example, in this StackOverflow response there are two
               | examples of a function 'partialsums':
               | 
               | https://stackoverflow.com/questions/37694313/make-ocaml-
               | func...
               | 
               | The one that Jeffrey Scofield provides is essentially
               | more efficient because the accumulated value is a list,
               | just like the end result, whereas my solution accumulates
               | a tuple, which means every iteration of the fold involves
               | boxing and unboxing that tuple. An optimizing compiler
               | working at a higher level of abstraction might figure
               | that out and re-use the memory of the tuple, but no sir.
        
             | hajile wrote:
             | The "real deal" here is Ocaml. It's not the most complex
             | syntax in existence, but I'd say it's _easily_ the most
             | complex ML language in existence.
        
         | jimbokun wrote:
         | > ReasonML seems to be just sugar coating for those with
         | aversion to ML classical syntax.
         | 
         | So it's the Elixir to Ocaml's Erlang?
        
           | firethief wrote:
           | Elixir is a different language for the Erlang VM, but Reason
           | is just a different syntax for the OCaml language. There's a
           | 1:1 correspondence between their ASTs, and even a tool to
           | convert between them.
        
       | hajile wrote:
       | ReasonML is adversely affected by it's Ocaml base if anything.
       | StandardML would have been a much better base (they went with
       | Ocaml because it was a lower-effort to implement and Facebook has
       | a lot of Ocaml devs).
       | 
       | The first bad part is that Ocaml _does not_ have a language spec.
       | The implementation is the spec. This puts them at the whim of the
       | Ocaml devs with no other options. SML is a standard with several
       | good implementations.
       | 
       | Ocaml requires different operators for float and integer
       | arithmetic. SML assumes an integer type unless you include a
       | decimal. Both need to be replaced with module typeclasses (and
       | both are working in that direction). For SML though, your
       | existing code can continue to just work as it did before while
       | Ocaml will be left with lots of `+.` or `*.` operators
       | everywhere.
       | 
       | Another mistake that bleeds through is mutable strings. This is
       | an outgrowth of all arrays being mutable. Immutable strings allow
       | efficient representation as ropes instead of normal arrays (along
       | with other optimizations that are good for GC'd languages). SML
       | has immutable strings and vectors along with arrays (which you
       | can still use as mutable strings of characters if you need them).
       | 
       | For their React-like goal though, Ocaml's lack of anonymous
       | record types is the absolute worst. In SML, I can just type up a
       | record and pass it in (no type definitions required). When
       | passing in stuff to a component, you have to have all these named
       | arguments. In SML, I'd just pass an anonymous record and
       | destructure it in the function -- Just like in Javascript, but
       | with types behind the scenes to keep everything straight.
       | 
       | Writing a custom parser for Babel like typescript or coffeescript
       | have done would have been better for the language design and
       | independence.
        
         | lindig wrote:
         | > Another mistake that bleeds through is mutable strings.
         | 
         | OCaml strings are immutable by default since OCaml 4.06.
        
         | vphantom wrote:
         | FYI strings are now immutable in OCaml. It was a compiler
         | option starting with 4.02 and it has become enabled by default
         | since 4.06.
        
           | hajile wrote:
           | That's nice to know. On the flip side, that's not nice for
           | interaction between older code that wants to mutate and newer
           | code that wants to "copy". If the "copy" code is actually
           | copying all the time behind the scenes (something it has to
           | do if you are compiling with mutable strings for backward
           | compatibility with the rest of your codebase), that's a huge
           | performance hit.
        
         | nv-vn wrote:
         | Well there is a language spec [1], it's just designed by the
         | same people who develop the compiler. While there's only 1 de
         | facto implementation (same as Rust, Go, etc.) there's multiple
         | backends and lots of research work happens in different forks
         | of the language. There's usually quite a bit of discussion and
         | work that occurs between proposing a feature and integrating it
         | into the language. There's also various competing forces here
         | such as INRIA, Jane Street, OCamllabs, Reason developers, &
         | other typical OCaml developers each with their own agenda. It's
         | not so simple as the devs just adding something without any
         | input.
         | 
         | >For their React-like goal though, Ocaml's lack of anonymous
         | record types is the absolute worst.
         | 
         | The object system actually allows this to be fair & it does get
         | a little bit of use in some Reason libraries targeting React
         | developers
         | 
         | I get that SML has advantages over OCaml but I don't really get
         | what you're trying to argue for. Clearly if you like SML you'd
         | prefer OCaml to JavaScript...
         | 
         | [1] https://caml.inria.fr/pub/docs/manual-ocaml/language.html
        
       | sweeneyrod wrote:
       | ReasonML is just an alternative syntax for OCaml. Often people
       | use "ReasonML" shorthand for "ReasonML, converted to OCaml,
       | compiled to Javascript with BuckleScript" and "OCaml" for "OCaml
       | compiled natively" but it's perfectly possible (and actually
       | really easy) to use OCaml with BuckleScript and Reason natively.
       | 
       | Also note that despite the "O" in the name, OOP in OCaml is rare
       | (for instance, there isn't any in the code in the article).
        
         | elcapitan wrote:
         | What's the state of using Reason natively? Last time I checked
         | all the documentation and examples where towards the
         | reason/js/react ecosystem. Are there any good native code
         | projects written in Reason to look at for reference?
        
           | k__ wrote:
           | Reprocessing is a rewrite of Processing in Reason.
           | 
           | Runs with WebGL and OpenGL.
           | 
           | https://github.com/Schmavery/reprocessing
        
           | sweeneyrod wrote:
           | People don't do it much, but if you're using the most popular
           | build system (dune) you can replace your .ml files with .re
           | ones and it will Just Work. So you can use OCaml projects for
           | reference (I think anyone who's doing Reason should have a
           | vague grasp of OCaml syntax, it's not really that different).
        
             | firethief wrote:
             | > I think anyone who's doing Reason should have a vague
             | grasp of OCaml syntax, it's not really that different
             | 
             | Especially if you're targeting native, so all your
             | dependencies are written and documented in OCaml syntax.
        
           | pcvonz wrote:
           | Check out Oni Vim 2:
           | https://github.com/onivim/oni2/blob/master/README.md
        
             | elcapitan wrote:
             | That looks perfect, thanks!
        
         | nv-vn wrote:
         | Yep. This is an especially weird thing for some people to grasp
         | when working with native libraries developed in Reason (like
         | Revery, which most people assume is built on web tech).
        
         | juliendemangeon wrote:
         | You're right! The toolbox is far better too
        
       | kingkonz1 wrote:
       | > it is very complicated to install the base stack to develop in
       | OCaml
       | 
       | I'm not sure why the author decided to use such a complicated
       | setup using Make and Docker.
       | 
       | They could have just ran `opam switch create 4.09.0`, which would
       | have created the compiler, then `opam install ...` for the
       | dependencies.
       | 
       | Still, an interesting article. I wouldn't recommending using
       | OCaml/ReasonML for gamedev since getting it to work with Windows
       | is pretty much impossible.
        
         | pnathan wrote:
         | It is complicated to figure out a straightforward way to do
         | builds in OCaml. If you're not tapped into the Current Way, you
         | kind of have to read this blog, read that fragment, piece it
         | together. I worked it through for a project of mine, and it was
         | unusually unpleasant vs, say, Haskell.
         | 
         | Docker because, presumably, he didn't want to dink with
         | installing it locally.
        
         | srpablo wrote:
         | While I didn't try to use Docker (though we did use the same
         | pxhere image :-p), I also struggled to get a productive setup
         | of OCaml. Getting a switch running wasn't the hard part, it was
         | making the environment suitable for real project work. I had a
         | set of Make targets in mind (test, build, shell), some language
         | dev features I wanted (jump to definition, type of expression
         | under cursor), and some properties of the project (pinned
         | dependencies) such that it took a fair bit of fiddling with
         | dune/opam to get it working
         | https://morepablo.com/2019/08/fresco-jesus-ocaml-setup.html
         | 
         | I find OCaml really enjoyable once I got going, but I do think
         | the initial setup is a major barrier to larger adoption. I
         | think a post on howistart.org might be useful, but it'd
         | probably be polarizing since most functions have two major ways
         | of doing it (Jane Street vs. not, Lwt vs. Async, etc.).
        
           | yodsanklai wrote:
           | I agree it's quite annoying to set up an OCaml project, and
           | all the Jane Street stuff makes it even more confusing for
           | newcomers. But to be fair, it may be the case with other
           | languages as well. I recently tried to learn some Javascript,
           | and I spent some time understanding the tooling and package
           | management (npm/yarn, bundling, transpiling, node vs browser,
           | difference between javascript versions).
        
             | nickserv wrote:
             | Modern JavaScript is a major pain to set up, but the
             | difference with other languages is that for some things
             | it's the only language available.
        
             | bryanrasmussen wrote:
             | This seems sort of like comparing the complexities of
             | learning German to a level of fluency with the complexities
             | of learning English, differences between major variant
             | forms of English, with a deep dive into the history of the
             | English Language and its poetics.
        
         | nv-vn wrote:
         | Agreed, the choice to use obuild was also bizarre. Dune has
         | been standard for the last ~2 years and before that Oasis was
         | the most popular build tool I believe.
        
       ___________________________________________________________________
       (page generated 2020-02-21 23:00 UTC)