Earlier quoted context omitted.
from personal experience with mypy, the great thing about gradual typing in a dynamic language is that, well, it's gradual! when I want to do something extremely dynamic, there's no horrible reflection API in my way. but most of the time I can live happily inside the walled garden mypy provides.
I have adopted this attitude for personal projects & small companies, and it was mostly great. There was at least 1 really large error that slipped into production because we were mocking an untyped service incorrectly (a mistyped property name), and the test passed, but prod exploded. It was embarrassing, and I certainly would have caught it with more mypy discipline, but overall the pros outweighed the cons. At big…
Ask HN: Who regrets choosing Elixir?
281–290 of 340 posts
Re: Ask HN: Who regrets choosing Elixir?
#282Right tool for the right job, I think. I’ve had absolutely wonderful experiences with Elixir doing web apps (both LoB style and SaaS style). Probably the best one, and it’s such a canonical example, is a group chat app using Websockets. It just feels so good, and with libcluster, multiple nodes in K8s can autodiscover and join each other. No problems at all having chats where the members are connected to websockets o…
That seems odd given that the BEAM was designed for reliable real-time telephone switching
Erlang is great at soft real-time but does not work at all for hard real-time, there simply are no guarantees, just very good average latency.
If you want hard real time (such as for in-flight control of a drone) then you should look elsewhere.
Re: Ask HN: Who regrets choosing Elixir?
#283Earlier quoted context omitted.
Trust your experience. It's impossible to defeat the claim that "with good tests you don't need static type checking", since every counter-example can be dismissed by arguing that better developers would have covered that test case. I can claim just the same that "with correct code you don't need tests", and dismiss every counter-example by arguing that better developers wouldn't have made that mistake. Obviously we…
Yeah. You formulated my opinion much more elegantly than I could've - in my experience it's always the "Well if the tests didn't catch this, we just aren't testing enough." Which in my experience is a losing strategy, you'll never test "enough" in languages like Ruby. In my experience this idea always brings a strawman, "Well in statically typed languages you still have to test", which is obviously true. But the type…
Maybe someone is saying that, but I didn't say that.
My question isn't whether you can test enough to catch all bugs. My question is whether time spent wrangling types gets you more value than time spent writing tests.
> But the type of tests and the content of the tests is very different.
Are they? How so?
Again, unit tests of the form `assert isinstance(foo, type)` are an antipattern--that's not what I'm proposing.
Re: Ask HN: Who regrets choosing Elixir?
#284Earlier quoted context omitted.
> When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages. I don't think that's a reasonable assumption at all. Even if, as you assert, the average person doesn't understand that types exist in dynamically-typed languages, I don't think that means I have to conform to common misconceptions. > Specs/contracts are cool but ultimate…
> the average person doesn't understand that types exist in dynamically-typed languages Again, this is needlessly uncharitable as to what people mean when they talk about type systems , which is obviously about the capabilities of defining new types for program analysis, not that the runtime has an internal conception of types. > Could you explain what descriptive and expressive power is missing here? Sure! Looking a…
> Again, this is needlessly uncharitable as to what people mean when they talk about type systems, which is obviously about the capabilities of defining new types for program analysis, not that the runtime has an internal conception of types.
There is nothing "internal" about the example I gave. That's valid Python code that creates a type.
My definition (which happens to be the actual definition of the word) charitably assumes that people know dynamic type systems exist, so I don't think you can really accuse me of being uncharitable. If anything I'm being too charitable, as evidenced by this conversation.
> Sure! Looking at this, I have no idea what the size of side_length is, whether it's possible for it to be negative, or whether it's possible it to be null.
> Of course, unless you're writing purely square based software, most domains are more complex than this. But I still think it's pretty helpful to know the properties of the parameters being passed to build your square are!
Do you really not know whether side_length can be negative or null? Or are you just saying that to be argumentative? If we're pretending we don't know obvious things, why not just go all the way and pretend we don't know that side_length is a number?
As for not knowing the size: why would you want to have to know the size? The fact that this square will work with any numeric type is a feature, not a bug.
Now, consider this (disclaimer: my C++ is rusty, and I didn't syntax check this):
class Square: Rectangle {
private:
double sideLength;
public:
Square(double sideLength) {
this.sideLength = sideLength;
}
}
Let's evaluate this based on your complaints about the Python example:1. The size of sideLength. Well, yes, this example does tell you what size it is. Which is rather annoying, since now you have to cast if you want to pass in an integer, and you might overflow your bounds. This is an annoyance, not a feature.[1]
2. We know that sideLength can't be negative because we know what squares are. The type doesn't enforce that. You could enforce that by using unsigned int, but then you can't handle decimals. And in either case, you can't use very very large numbers. I haven't worked in a static typed codebase which has an unsigned BigDecimal type, have you?[1]
3. We know that sideLength can't be null because we know what squares are. The type system technically also tells us that, but the type system telling us what we already know isn't particularly useful.
[1] Haskell's numeric type can actually handle this much more cleanly than C++, as I mentioned upthread. But in typical Haskell, you'd probably just let the types be implicit in a lot of cases.
Re: Ask HN: Who regrets choosing Elixir?
#285Earlier quoted context omitted.
>> When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages. Really? You're going to go with "most languages implement static typing"? That seems like a bold statement.
I'm not making a claim about all languages, I'm talking about languages that support any kind of extensible type validation, whether statically or at runtime.
Re: Ask HN: Who regrets choosing Elixir?
#286Earlier quoted context omitted.
> I see that language parroted all the time - "With thorough enough testing a dynamic language shouldn't be a problem", and I have never understood it. "If you drive carefully enough, a car without seatbelts shouldn't be a problem!"
Exactly
If you're writing software that's life and death critical like wearing a seatbelt, you should absolutely be using a strong, statically typed language, because catching errors at runtime is completely unacceptable. But incidentally, none of the proponents of static types on this thread have talked about any languages that I would actually use for this situation. Java or C-family languages certainly aren't strongly typed enough. Type systems aren't a magic bullet.
But in the vast majority of modern software, it mostly just matters that you catch and fix bugs quickly--whether you catch those bugs at compile time or runtime is usually not as critical.
Re: Ask HN: Who regrets choosing Elixir?
#287Earlier quoted context omitted.
> If I'm a great java developer with tons of jobs to choose from, you are going to have to give me a very good reason to narrow my opportunities down for you. Why would learning a new tool narrow rather than widen your opportunities? It's not like you forgot all you know about Java.
Learning an obscure tool that eventually dies is a waste of time. Think learning a language only you and a few of your friends speak. This in itself is good enough reason to be cautious about what you invest your time in learning. Languages and specially the tool chain and the way of doing things around them evolve. If you spend like 5 years doing something else and come back to it, you'll find things have changed a…
That is only if it's actually useless. I haven't programmed in haskell for many years, yet I am very glad I did. It was hard at first, but it made me think about code, data and transformation from a different perspective, expanding the repertoire of paradigms, regardless of which language I code in.
YMMV, but personally, I'd much rather hire or work with someone with 3y java + 1y erlang experience, than just 5y java experience. In general a polyglot rather than monoglot, especially if it's a different coding paradigm. Nevertheless, I may not actually want them coding random bits of work in erlang or whatever random language.
Re: Ask HN: Who regrets choosing Elixir?
#288Earlier quoted context omitted.
> When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages. I don't think that's a reasonable assumption at all. Even if, as you assert, the average person doesn't understand that types exist in dynamically-typed languages, I don't think that means I have to conform to common misconceptions. > Specs/contracts are cool but ultimate…
> Could you explain what descriptive and expressive power is missing here? tldr: i haven't seen a runtime typechecker that handles generics and function types in a satisfactory manner. i've used various Python libraries for runtime type-checking (based on `typing` annotations) like `typeguard`. and they work okay for simple types, but suck for anything involving generics and function types. checking if something is a…
Let's just stop right there, since it's immediately clear you aren't answering the question I asked. You're talking about type checking, not descriptive and expressive power.
The topic is whether dynamic types are suitable for domain modeling, not whether dynamic types provide static type checking. We all agree that dynamic types don't provide static type checking.
Re: Ask HN: Who regrets choosing Elixir?
#289I’ve played with Elixir/Phoenix a little bit and was not very happy with a few things: - Debugging is hard. You can’t throw a REPL wherever your want in your code and pipe states are hard to inspect. - Serving static files in Phoenix is oddly super hacky. - Deploy is hard. Mostly by the lack of support out there in term of documentation and services.
1. IEx.Pry, if you are used to ruby's pry. Pipe states are extremely easy to inspect: abc |> foo() |> bar() to abc |> IO.inspect(label: "a") |> foo() |> IO.inspect(label: "b") |> bar() |> IO.inspect(label: "c") If you use vscode, this user snippet will inject this (with line numbers as labels) when you type "ins ", which can be used to great effect with multiline cursors. Since line numbers are usually the same lengt…
I clearly hadn't bothered to read the 'Getting Started - Debugging' page on the Elixir website at any point.
Re: Ask HN: Who regrets choosing Elixir?
#290Earlier quoted context omitted.
I've seen this too, but I tend to think of it as an antipattern. The fact is, in most cases a Python function won't carry on as normal if you feed it an unexpected type, because while Python's type system isn't static , it is fairly strong . In general I am a fan of strong types and I would like it if Python's type system were a lot stronger. But ultimately this isn't what my post was about: I'm talking about modelin…
What do you mean it's fairly strong? Not challenging you, I'm just trying to get my head around all the type stuff.
~/$ python
Python 3.7.4 (default, Oct 12 2019, 18:55:28)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> hello = 'Hello, world'
>>> one = 1
>>> hello + 1
Traceback (most recent call last):
File "", line 1, in
TypeError: can only concatenate str (not "int") to str
To put this in context, type systems can be roughly divided into 4 categories along the strong/weak and static/dynamic axes:1. Strong static types (makes a lot of assertions about type, checks these assertions at compile time; Haskell, ML, OCaml, Rust, C# are reasonable examples--Haskell folks would probably laugh at me including C# here, but it's the only example in widespread non-academic use). Example (C#):
var hello = "Hello, world";
var one = 1;
var result = hello + one // Doesn't compile
2. Strong dynamic types (makes a lot of assertions about type, checks these assertions at run time; Python is the best example I have, but to be honest, it's not a great example--I think the type system could be a lot stronger). See the Python code above for an example.3. Weak static types (makes few assertions about type, checks these assertions at compile time; C, C++ are good examples, although it's arguable that C actually does more checking at run time than at compile time). Example (C):
char* hello = "Hello, world";
int one = 1;
char* result = hello + one; // Happily compiles
4. Weak dynamic types (makes few assertions about type, checks these assertions at run time; JavaScript is a great example of this). Example (JavaScript): >>> var hello = "Hello, world"
undefined
>>> var one = 1
undefined
>>> hello + 1
"Hello, world1"
In general, I have a slight preference for static types over dynamic types, but I think that difference is overrated. I care a lot more about my preference for strong types over weak types.