Hacker News new | past | comments | ask | show | jobs | submit login

> You can see a bit of what the macro system enables here

The first thing that struck me about this post is that it is a good illustration for why dynamic-typing people and static-typing people often butt heads:

Most static typing we see is shallow like this, where the concern is to shove data into an unstructured object like a String, and the problem is something trivial.

In this case, String? solves the immediate problem of whether or not the value is really nil, but it fails to consider other aspects:

- Are you really intending to remove the country code from just US numbers? Or all North American ones? Quite possibly you're ok with stripping it from all North American ones rather than just US ones, but if not (e.g. because you later use the presence or absence of a country code to differentiate on billing), it does the wrong thing

- Does the code otherwise enforce a format where "+" can not appear elsewhere? (because someone e.g. decided to use it as a non-standard separator) Does it ensure nobody has input country codes without a "+"? (I've lost count of the number of times I've seen just "1" or (1)). Does it ensure nobody has used spaces? ("+ 1"). What about the number after that - it does nothing to prevent the returned local number from having consistent formatting.

Maybe this is all ok in the code you looked at and the data is guaranteed to only ever have "+1" and be nicely formatted when you strip it.

But it is a really bad way of selling static typing as a feature of the framework, as my first reaction is "but it gives me nothing, as there are all kinds of other checks I also need to do".

Which means either modelling the type of the data much more precisely - which I can do with or without static typing - and/or building a test suite that includes testing any places where data can get put into that table in the first place.

In both cases the kind of problems above tends to fall away with little to no effort.

I'm all for typing used for data validation, but an example showing what more precise modelling would look like would be a lot more convincing.

E.g. I detest Haskell syntax, but one of the strengths of static typing as Haskell developers tends to apply it, is that there tends to be a lot more focus on the power that comes from more precisely modelling the data.




TL;DR I totally agree. This can be done with Crystal and Lucky but I wanted to keep the example simple.

I totally agree with your sentiment and you have a lot of great points. This post was not meant to get too deep into things right off the bat, so it left off a lot of this stuff.

In this case the phone number always has a country code with +1 because we have a validation that ensures it won't make it into the database without it. We also only accept US country codes in the validation.

I get your point though that just having a `String` doesn't really guarantee that those validations took place, luckily, LuckyRecord has the idea of custom types that can define their own casting and validation behavior. So we could have done this:

``` field phone : UnitedStatesPhoneNumber? ```

And it would validate that the string param is a valid US number before saving. It would also do that for queries and you could add whatever other type specific methods you want to it. so you could do

``` def formatted_fax_number phone.try { |number| number.without_country_code } end ```

But like I said, I think this is fitting for a whole separate post, rather than an intro style post :D


And for a Ruby/Elixir/dynamic lang programmer just catching `nil` is actually a pretty big win, even without the custom type.

I will go more into depth about leveraging the type system with Lucky for even better data modeling in one of the Lucky guides


I just think it makes it a lot less interesting to cover that kind of intro use case, as it's not very compelling exactly because of reactions of "but that's not how I'd do it".

Even more so because the "try" syntax is exaggerated. This works fine:

    fax_number.try(:gsub,"+1", "")
And with a new enough version of Ruby, this works too:

    fax_number&.gsub("+1","")
You still need to remember to do it of course, but using the "old" syntax makes the problem seem exaggerated.


Only replying to your last point.

I had a chance to see static typing benefits in action and I will always agree they are a bit ahead of the dynamic typing.

That being said, I feel static typing is a bit overrated in web dev and outside of enterprise systems overall. F.ex. when I tried to quickly immerse myself in Elm, I figured that obsessiveness with static typing can make a dev's life very miserable and can basically require doing cartesian product structs for many scenarios -- especially if you have to work with data coming from several API providers and provide API yourself to users whose requirements are periodically changing.

I might be a bit in a fanboy mode here I admit, but the compromises that Erlang / Elixir do seem very adequate -- they do forgo some of the benefits of the static typing in return for a bit more productivity / less friction. Granted, if you are irresponsible then you can easily shoot yourself in the foot with them as well. No magic bullets.

(Conversely, if you apply some discipline -- which is still probably two orders of magnitude less than the discipline you need in C/Cpp -- then Erlang / Elixir's dynamic typing is almost like static typing.)

This isn't a blind hate towards static typing; having exposed myself for educational purposes for limited amounts of time to Elm, Pony, Crystal and just an hour of Haskell -- and having worked with Go professionally for several months -- I am not as impressed as I expected to be. I clearly see the benefits but again, I feel they are a bit overrated. A language with a reasonable compromise between type safety and programmer productivity seems to be my cup of tea. And I am not claiming that this "reasonable compromise" -- which is a very subjective term -- is an universal truth. Not at all.

Lastly, Elixir's macro system is not hugely powerful (at least compared to what I know about Clojure) but has served all semi-arcane tasks I tried -- and succeeded -- to achieve with it. But that's of course very specific to one's work and it too can't be claimed as an absolute truth.

Not willing to derail here. Your mention of Haskell triggered a few associations. Apologies if the comment is out of place / topic.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: