I'm still fighting with Elixir and losing - for some reason I can't get my head around all the slightly different ways to initialise stuff.
can you elaborate? theres only what 11 datatypes in elixir?
21–30 of 163 posts
I'm still fighting with Elixir and losing - for some reason I can't get my head around all the slightly different ways to initialise stuff.
can you elaborate? theres only what 11 datatypes in elixir?
Isn't the whole point of abstraction to not care about whats underneath unless you really have to? But ideally, you don't because the abstraction is "good enough"? I haven't heard anyone writing code in Elixir complain about performance issues.
What’s up with the last paragraph? Nobody is complaining because the BEAM is good enough for the typical use case?
btw we do sometimes bitch about performance :)
io is not a monad. theres nothing stopping you from stashing a global io "object" and just passing the global wherever you interface with the stdlib. It's dependency injection . and yes, you can model dependecies like a monad but most people, even in less pure fp langs, don't. i don't really say this to just be a pedant, but if you're an fp enjoyer, you will be disappointed if you get the picture that zig is fp-like,…
Earlier quoted context omitted.
This looks like an example of a low level language vs a high level language (relatively speaking). The low level language makes a lot more of what is going on underneath explicit compared to the higher level language which abstracts that away for a common pattern. Presumably that explicitness allows for more control and/or flexibility. So apples to oranges?
I don't think so, where's the extra information in the Zig example? In Rust, which is arguably also a low level language, it looks like this: enum Option { None, Some(T), }
In Zig, that means being able to use the language itself to express type level computations. Instead of Rust’s an angle brackets and trait constraints and derive syntax. Or C++ templates.
Sure, it won’t beat a language with sugar for the exact thing you’re doing, but the whole point is that you’re a layer below the sugar and can do more.
Option is trivial. But Tuple? Parameterizing a struct by layout, AoS vs SoA? Compile time state machines? Parser generators? Serialization? These are likely where Zig would shine compared to the others.
I actually ship stuff in Haskell believe it or not. I also think Zig is very cool and have played around with it quite a bit. Yes, garbage collection hurts performance, but the reality is that the overwhelming majority of all software does not suffer from the performance loss between well written code in a reasonably performant functional gc language and a highly performant language with manual memory management. It’s just not important. But not having to deal with the cognitive overhead of managing memory and being able to deal in domain specific abstractions only is a massive win for developer productivity and code base simplicity and correctness.
I think OxCamls approach of opting in to more direct control of performance is interesting. I also think it’s great that many functional patterns are making their way into imperative first languages. Language selection is always about trades offs for your specific use case. My team writes Haskell instead of Rust because Haskell is plenty fast for our use case and we don’t have to write lifetime annotations everywhere and think about borrowing. If we needed more performance we would have no choice but to explore other languages and sacrifice some developer experience and productivity, that’s very reasonable. I’m also not saying performance doesn’t matter (if you’re writing for loops in Python, stop). But this read to me like “because better performance exits with manual memory management, all garbage collectors are bad, so I’ll force zig to be something it’s not in order to gain performance I probably don’t need”. Which to me is an odd take. A more measured way of thinking about this might be, it can be useful to leverage functional patterns where appropriate in low level languages, if you find yourself needing to write code in one.
Earlier quoted context omitted.
Optionals handle this in zig: var value: ?T = null; Write: value = 10; Read: if (value) |x| x+=1
Sure, but this is an example from the article, and pertains to sum types in general, not just Maybe.
the annoyingness of the thing you tried to do in zig is a feature. its a "don't do this, you will confuse the reader" signal. as for optional, its a pattern that is so common that it's worth having builtin optimizations, for example @sizeOf(*T) == @sizeOf(usize) but @sizeOf(?*T) != @sizeOf(?usize). if optional were a general sum type you wouldn't be able to make these optimizations easily without extra information
Do you really prefer this: fn Maybe(comptime T: type) type { return union(enum) { value: T, nothing, const Self = @This(); pub fn just(the_val: T) Self { return .{ .value = the_val }; } pub fn nothing() Self { return .nothing; } } } Over this? data Maybe a = Just a | Nothing
Optionals handle this in zig: var value: ?T = null; Write: value = 10; Read: if (value) |x| x+=1
io is not a monad. theres nothing stopping you from stashing a global io "object" and just passing the global wherever you interface with the stdlib. It's dependency injection . and yes, you can model dependecies like a monad but most people, even in less pure fp langs, don't. i don't really say this to just be a pedant, but if you're an fp enjoyer, you will be disappointed if you get the picture that zig is fp-like,…
I am not even sure if its a general pattern (inject any dependency?) or a specific pattern they added to Zig
here. i am not the only one that refers to it as dependency injection:
https://daily.dev/blog/zig-async-io-io-uring-zig-0-16-rethin...
"Zig 0.16 introduces std.Io, a flexible I/O abstraction that uses dependency injection, similar to the Allocator interface"