Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Swift has a typealias keyword but it's not really useful for this since two distinct aliased types with the same underlying type can be freely interchanged. Wrong code may look wrong but it will still compile.

Wrapper structs are the idiomatic way to achieve this, and with ExpressibleByStringLiteral are pretty ergonomic, but I wonder if there's a case for something like a "strong" typealias ("typecopy"?) that indicates e.g. "this is just a String but it's a particular kind of String and shouldn't be mixed with other Strings".



Yeah, most languages I've used are like this. E.g. rust/c/c++.

I guess the examples in TFA are golang? It's kind of nice that you don't have to define those wrapper types, they do make things a bit more annoying.

In C++ you have to be extra careful even with wrapper classes, because types are allowed to implicitly convert by default. So if Foo has a constructor that takes a single int argument, then you can pass an int anywhere Foo is expected. Fine as long as you remember to mark your constructors as explicit.


Rust has the newtype idiom which works as proper type alias most of the time


Both clang-tidy and cpplint can be configured to require all single-argument constructors (except move, copy, and initializer-list constructors) to be marked explicit, in order to avoid this pitfall.


This sounds elegant in theory but very thorny in practice even with a standards change, at least in C++ (though I don't believe the issues are that particular to the language). Like how do you want the equivalent of std::cout << your_different_str to behave? What about with third-party functions and extension points that previously took strings?


Isn't that where C++20 concepts come in?


Haskell has this, it's called newtype.

In OOP languages as long as the type you want to specialize isn't final you can just create a subclass. It's cheap (no additional wrappers or boxes), easy, and you can specialize behavior if you want to.

Unfortunately for various good reasons Java makes String final, and String is one of the most useful types to specialize on.


But then you are representing two distinct types as the same underlying type, String.

  MyType extends String;
  void foo(String s);
  foo(new MyType()); // is valid
Leading to the original problem. I don't want to represent MyType as a String because it's not.


It has to work that way or else you can't use the standard library. What you want to block is not:

    StringUtils.trim(String foo);
but

    myApp.doSomething(AnotherMyType amt);
The latter is saying "I need not any string but a specific kind of string".


No I want to block both. I don't want to give devs the option of creating a function doSomething(String) that happens to accept MyType. If I need to call trim then I'll do

  StringUtils.trim(MyType.toString());


In what precise way are you envisioning that this would be different from a wrapper struct?


Pretty much only less boilerplate. Definitely questionable if it's worth the added complexity. And also it could probably be a macro.




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

Search: