A few notes:
> It looks like it fuzzes immutability (you can redefine variables).
This is a really minor of a issue in practice. All data structures are still immutable by default, and when actually using the language, it's really rare for a function to reach long enough that tracking variable values becomes cumbersome. In the end, it's a tradeoff between that and having to juggle tons of variable names like it can happen in Erlang code (again, it usually doesn't).
Outside of that, Elixir is exactly as immutable as Erlang, which is to say, with tons of escape hatches (yes, even that last link).
> I'd be less confident in the mapping & coverage to BEAM vs something thats been in production for 20 years.
Fair enough, but Elixir strongly follows conventions from the larger OTP ecosystem. It's not just using BEAM as a cool VM like some languages do with other VMs (Scala comes to mind).
Elixir is really Erlang with nice metaprogramming and nicer syntax for people who never saw Prolog in their lives (that's where Erlang syntax comes from - the first prototypes were made with it and the creators (AFAIK) liked Prolog syntax).
> But that latter function makes me squirm, thinking about the performance and memory impact of re-creating a complex game state data container structures 60x a second
It doesn't have to be recreated from scratch, your old state and the new one can share most data. Structural sharing is the keyword.
> The other area of conflict is whether data and function should be packaged together vs. apart
Functions can also be grouped together with data in a purely functional language. The difference to OO is that in a functional language you can't have a this
pointer, as that wouldn't make any sense.
> I am struggling to imagine how an FP design would gracefully handle such a ad hoc, loose confederation of dynamic parts
Via isolated processes that communicate via messages. You might want to look at erlang and elixir.
Changes (some copied from rc1 not necessarily just in rc2):
maps, maps, maps (docs here: https://www.erlang.org/eeps/eep-0043.html)
The default encoding of Erlang files has been changed from ISO-8859-1 to UTF-8.
{active,N} options for sockets
Experimental "dirty schedulers" functionality (good for those writing NIFs)
Funs can now be given names
A new versioning scheme (if you couldn't tell by the title)
FWIW, as someone used to Elixir (and sometimes lucky enough to use Erlang), the WxWidgets bindings in those languages are mature and included in the standard library. Including a GL canvas and a pretty complete GL library binding. See https://www.erlang.org/doc/man/wxglcanvas They also tend to take software quality and lifecycle more seriously than most.
Where it falls short is when you need custom widgets or do something computationally intensive. Which led me in turn to use F# with OxyPlot/Gtk and Akka.NET on Linux which so far has been a really great platform.
Avalonia is also starting to look somewhat usable, although for my use case the OxyPlot.Avalonia/Avalonia.Skia combination was unbearably slow compared to OxyPlot.Gtk.
Hmm, so what am I trying to say? Try out Avalonia with different backends like X11 as well. And You can get pretty far with wx in Erlang/Elixir without doing any manual bindings.
Best of luck!
Guile is a kind of scripting language to make it easy to handle loading plugins into apps. It makes it possible to think of an app as a minimal 'core' application which is really just a host for plugins. I have to be honest, i don't really know exactly what Guile is - but i thought it might interest you.
A completely different thing, but which also might interest you is the Erlang Language (or Elixir if you would rather have a ruby-like flavour). In Erlang, Robustness and fault tolerance are the ultimate aim, and this is approached by conceiving of 'the application' as instead small stand-alone applications that send messages to each other. Failure of one part can't affect the others, and a single app can just as easily be spread over many machines (message sending doesn't really care if the recipient is on the same node or over a network).
just a couple of thoughts
Erlang’s = operator works this way: https://www.erlang.org/doc/reference_manual/patterns.html.
But that’s because it’s semantically a pattern match operator that always destructures. If the variable value isn’t set, it sets it. If it is, it evaluates the equality for truth, exactly how it’s worked in math and logic for 200 years.
The fact that this is weird in programming languages is pretty frustrating.
If this is some sort of struct it is good practice to use a `new` function and then you could just use a guard clause:
defmodule Phone do
defstruct :number, :state
def new(number, state)
when state in [:ringing, :voicemail, :talking, :inactive, :hold do
%__MODULE__{
number: number,
state: state
}
end
end
If you are accepting user input I would just use Ecto Changesets & Schemas.
If you are actually modelling a state machine you could look into <code>gen_statem</code> which is very nice for modelling state machines.
If you look at the documentation for file:open/2, you will see that it returns either {ok, IoDevice}
or {error, Reason}
. Your code tried to use f
on the left side of the equals. In Erlang, f
is an atom. You need to remember that variables start with an upper case letter in Erlang, or F
in this case.
But then you are unable to pass that directly into file:write/2
because the open function returned {ok, IoDevice}
, you will need to pattern match in order to get the file. The following code should work for you
{ok, F} = file:open("targetfile", [write]), file:write(F, "on no"), file:close(F).
With that said, I don't know if that will help you with the CVE.
Project Euler problem #277 describes a sequence, defined by these rules:
> A modified Collatz sequence of integers is obtained from a starting value a1 in the following way:
> an+1 = an/3 if an is divisible by 3. We shall denote this as a large downward step, "D".
> an+1 = (4an + 2)/3 if an divided by 3 gives a remainder of 1. We shall denote this as an upward step, "U".
> an+1 = (2an - 1)/3 if an divided by 3 gives a remainder of 2. We shall denote this as a small downward step, "d".
> The sequence terminates when some an = 1.
I used Erlang (long story) to emit a dot-format file, and rendered it with GraphViz, to try to build intuition about the problem. This is the result.
References