Hacker Newsnew | past | comments | ask | show | jobs | submit | vips7L's commentslogin

.net has been able to ship the runtime with your app for years.

It's quite genuinely a pleasant language.

I was learning it and having a great time with it. Unfortunately the job market for it is abysmal. And in 2026 with the current state of the job market I didn't want to focus my time on something that wouldn't help me to get a job. But still the most fun I have had with a language.

Not who you asked, but I decided to try F# after reading “Domain Modeling Made Functional” which uses F# and is one of the best books I’ve read on domain driven design. I cannot recommend it more.

That being said, F# wasn’t really for me and applying the ideas from the book into other languages has been a better fit for me.


Thanks for your comment. What about the team? I mean, it's not just for one member right?

    record PhoneNumber(String value) {}

Huge pain.

I’m very much a proponent of statically typed languages and primarily work in C#.

We tried “typed” strings like this on a project once for business identifiers.

Overall it worked in making sure that the wrong type of ID couldn’t accidentally be used in the wrong place, but the general consensus after moving on from the project was that the “juice was not worth the squeeze”.

I don’t know if other languages make it easier, but in c# it felt like the language was mostly working against you. For example data needs to come in and out over an API and is in string form when it does, meaning you have to do manual conversions all the time.

In c# I use named arguments most of the time, making it much harder to accidentally pass the wrong string into a method or constructor’s parameter.


In f# you can use a single case discriminated union to get that behaviour fairly cheaply, and ergonomically.

https://fsharpforfunandprofit.com/posts/designing-with-types...


What have you gained?

Without any other context? Nothing - it's just a type alias...

But the context this type of an alias should exist in is one where a string isn't turned into a PhoneNumber until you've validated it. All the functions taking a string that might end up being a PhoneNumber need to be highly defensive - but all the functions taking a PhoneNumber can lean on the assumptions that go into that type.

It's nice to have tight control over the string -> PhoneNumber parsing that guarantees all those assumptions are checked. Ideally that'd be done through domain based type restrictions, but it might just be code - either way, if you're diligent, you can stop being defensive in downstream functions.


> All the functions taking a string that might end up being a PhoneNumber need to be highly defensive

Yeah, I can't relate at all with not using a type for this after having to write gross defensive code a couple of times e.g. if it's not a phone number you've got to return undefined or throw an exception? The typed approach is shorter, cleaner, self-documenting, reduces bugs and makes refactoring easier.


>But the context this type of an alias should exist in is one where a string isn't turned into a PhoneNumber until you've validated it.

Even if you don't do any validation as part of the construction (and yeah, having a separate type for validated vs unvalidated is extremely helpful), universally using type aliases like that pretty much entirely prevents the class of bugs from accidentally passing a string/int typed value into a variable of the wrong stringy/inty type, e.g. mixing up different categories of id or name or whatever.


one issue is it’s not a type alias but a type encapsulation. This have a cost at runtime, it’s not like in some functionnals languages a non cost abstraction.

Correctness is more important than runtime costs.

In languages like kotlin and rust you can have a type encapsulation like this that does not exist at runtime

Validation, readability, and prevention of accidentally passing in the wrong string (e.g., by misordering two strings arguments in a function).

I don't see any validation here.

An explicit type

Obviously the pseudo code leaves to the imagination, but what benefits does this give you? Are you checking that it is 10-digits? Are you allowing for + symbols for the international codes?

Can't pass a PhoneNumber to a function expecting an EmailAddress, for one, or mix up the order of arguments in a function that may otherwise just take two or more strings

You have functions

    void callNumber(string phoneNumber);
    void associatePhoneNumber(string phoneNumber, Person person);
    Person lookupPerson(string phoneNumber);
    Provider getProvider(string phoneNumber);
I pass in "555;324+289G". Are you putting validation logic into all of those functions? You could have a validation function you write once and call in all of those functions, but why? Why not just parse the phone number into an already validated type and pass that around?

    PhoneNumber PhoneNumber(string phoneNumber);
    void callNumber(PhoneNumber phoneNumber);
    void associatePhoneNumber(PhoneNumber phoneNumber, Person person);
    Person lookupPerson(PhoneNumber phoneNumber);
    Provider getProvider(PhoneNumber phoneNumber);
Put all of the validation logic into the type conversion function. Now you only need to validate once from string to PhoneNumber, and you can safely assume it's valid everywhere else.

Remember that the ancestor gave a pointless wrapper class plus the sarcastic remark "Huge pain."

That's going to be up to the business building the logic. Ideally those assumptions are clearly encoded in an easily readable manner but at the very least they should be captured somewhere code adjacent (even if it's just a comment and the block of logic to enforce those restraints).

How to make a crap system that users will hate: Let some architecture astronaut decide what characters should be valid or not.

And parentheses. And spaces (that may, or may not, be trimmed). And all kind of unicode equivalent characters, that might have to be canonicalized. Why not treat it as a byte buffer anyway.

If you are not checking that the phone number is 10 digits (or whatever the rules are for the phone number for your use case), it is absolutely pointless. But why would you not?

I would argue it's the other way around. If I take a string I believe to be a phone number and wrap it in a `PhoneNumber` type, and then later I try to pass it in as the wrong argument to a function like say I get order of name & phone number reversed, it'll complain. Whereas if both name & phone number are strings, it won't complain.

That's what I see as the primary value to this sort of typing. Enforcing the invariants is a separate matter.


What did you lose?

Love seeing some nushell usage!

No they’re not.

These people live on another planet.


It seems to be a common place of residence lately.


Depends on the D compiler. The reference compiler optimizes for compilation speed. LDC is backed by llvm and gdc by gcc.


Checked exceptions are proper errors as data. There is no difference between Result[T, E] and T throws E. The same people that just rethrow as RuntimeException would call unwrap() on Result and panic. The main problem with _Java_'s implementation of checked exceptions is that they're not fully in the type system because of Java's weak type system. That is solvable with a strong type system though, like in Scala or Swift.


Sounds like enums with extra steps.


Enums aren't type safe in typescript


Sounds like a major flaw.


it’s Enuma associated with data without having to repeat yourself

If you have to define the Enums in one place and then repeat them all in another just to associate data with each one you’ve failed


Maybe you can elaborate but enums in Java or Kotlin easily have data associated with them.

    enum class Color(val rgb: Int) {
        RED(0xFF0000),
        GREEN(0x00FF00),
        BLUE(0x0000FF)
    }


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

Search: