this post was submitted on 18 Nov 2024
20 points (73.8% liked)

Programming

17668 readers
138 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities !webdev@programming.dev



founded 2 years ago
MODERATORS
all 16 comments
sorted by: hot top controversial new old
[–] traches@sh.itjust.works 41 points 1 month ago (1 children)

I don’t get the hatred for types, they have saved my ass so many times and saved so many headaches exactly like what the article describes. I used to write a lot of ruby and after getting decent at typescript I can’t go back.

It’s not just ceremony, types ensure some level of logical consistency in your app. They reduce how much of the world you need to keep in your head at one time, and they allow you to express your intent far more robustly than comments and naming can. I love rust’s approach of making invalid state not even representable.

[–] bradboimler@lemmy.world 2 points 1 month ago

Designing custom types are one of my favorite things about programming

[–] dohpaz42@lemmy.world 19 points 1 month ago* (last edited 1 month ago) (3 children)

Instead of just doing what I want to do, I'm stuck either doing plumbing work to hold my values and pass them around, or I'm casting things back and forth where I know things are correct but the compiler doesn't.

I hate this attitude.

Instead of doing what you want to do? Dude, unless you’re a hobbyist, you’re being paid to do what your company wants you to do; i.e., it’s not about what you want.

Stuck doing plumbing work? Yeah, nobody likes plumbing, but we all know it’s necessary. When you’ve got your proverbial shit backing up onto your floor because you cheaped out on plumbing, cry to me then.

If you’re casting things back and forth, you’re doing it wrong. Spend a day or two and build yourself a solid, consistent foundation, plan ahead, and you won’t be casting things back and forth.

And no, you obviously don’t know better than your compiler, you arrogant sack of sh…

Anyway, get over yourself already and just do your damn job better.

[–] traches@sh.itjust.works 7 points 1 month ago

I mean I agree but you don’t have to be a dick about it

[–] TehPers@beehaw.org 12 points 1 month ago

Types aren't unit tests. Unit tests only test a discrete set of inputs and outputs for correctness, and can miss cases that aren't tested for.

In sound type systems, they are closer to formal verification. The compiler guarantees the properties you expect of the type hold.

As for the rest of the article, do what works best for you in your projects, but if I need to work with you, I'm going to ask for types. I need to know what types the interface expects to receive. Names are not enough. Document them, use type hints, whatever, just put them somewhere because I'm not psychic and I don't know what you thought about when writing the function.

[–] Kissaki@programming.dev 6 points 1 month ago* (last edited 1 month ago) (2 children)

Seems like a Ruby issue and suggested improvement? Using keyword arguments does feel like introducing a type of typing.

In C# I use records for simple, naturally behaving types, I can define explicit and implicit cast operators, so I have to choice between requiring explicit casts or not (because they make sense to require or are not necessary). I can use var to define a variable without specifying a type, and it is deducted from what it gets assigned - but is still that specific type and gives me type safety.

In Rust, as far as I understand anyway, traits define shared behavior. In Go interface implementations are implicit rather than explicit. With these, there's even less of a need of elaborate explicit typing like the post argues/gives an example of.


In general, I've never had considerable effort or annoyance implementing or using typing. And I know what it's good for; explicitness, and in consequence, predictability, certainty, increased maintainability, and reduced issues and confusions. If following references or refactoring becomes unpredictable or high effort, it'd be quite annoying.

When I'm coding JavaScript adding JSDoc so the typing information gets passed along is quite cumbersome. Without it, the IDE does not give intellisense/auto-completion or argument type matching. JavaScript is better with it, I consider it worth it with IDE support, but it is quite cumbersome. (I try to evade TypeScript compiler/tooling overhead.)

A programming language can offer extensive auto-deduction while using strong typing. With appropriate conversions in place, it will only report conflicts and where it was intended to.


I'm thinking of where I enjoyed dynamic natures, which I certainly have. But I don't think that's a matter of typing. It's a matter of programming language interfacing to typing. If in PHP or JS I make a change, hit F5, and get an error, that's not any better than the IDE already showing it beforehand. And for the most part, I can program the same way with or without typing.

Man, this became a long text.

[–] Ephera@lemmy.ml 3 points 1 month ago

In Rust, as far as I understand anyway, traits define shared behavior.

They're certainly the concept closest to e.g. C#/Java interfaces. But you can also define shared behaviour with enums, as Rust's enums are on steroids.

Basically, let's say you've got two existing types TypeA and TypeB for which you want to define shared behaviour.

Then you can define an enum like so:

enum SharedBehaviour {
    A(TypeA),
    B(TypeB),
}

And then you can define the shared behavior with an impl block on the enum:

impl SharedBehaviour {
    pub fn greet(&self) {
        match self {
            SharedBehaviour::A(type_a) => println!("Hi there, {}!", type_a.name),
            SharedBehaviour::B(type_b) => println!("Hello, {}!", type_b.metadata.forename),
        }
    }
}

On the flipside, Rust doesn't have superclasses/inheritance for defining shared behaviour.

[–] TehPers@beehaw.org 3 points 1 month ago

If in PHP or JS I make a change, hit F5, and get an error, that's not any better than the IDE already showing it beforehand.

This is even worse because it can happen in prod without you ever triggering this case. For some projects, it doesn't matter because the impact of a bug is small. For most, you put a subpar, buggy experience in front of your users, waste more time looking for the cause and debugging later with upset users, and at worst cause actual damages (depending on the project anyway).

[–] NigelFrobisher@aussie.zone 4 points 1 month ago (1 children)

This was always the trade-off of dynamic languages. You have to write a lot more unit tests to prove basic correctness, but you can move quickly at first if you’re not bothered about that.

[–] Ephera@lemmy.ml 4 points 1 month ago

I feel like this has somewhat shifted in recent years. Due to type-aware IDEs/editors being pretty much universal now, having types speeds you up in that initial phase, too. And type inference eliminates much of the inertia, too.