News for hackers. Stuff that matters.
Re:Don't Be Afraid of Types by motorest on Saturday March 22, 2025 @01:47AM (#43443845)
> Every darn little thing in Java needs a name.

Don't all types need names, regardless of what language you use?

Look at typescript, and how it supports structural typing. They don't seem to have a problem with names. Why do you think Java has that problem when nominal type systems simplify the problem?

> There's no need to declare a type ObjectWithFirstNameAndLastName. It would be quite silly.

Naming things is hard, but don't criticize typing for a problem caused by your lack of imagination. A basic fallback strategy to name specialized types is to add adjectives. Instead of ObjectWithFirstNameAndLastName you could have NamedObject. You don't need to overthink it, with namespaces and local contexts making sure conflicts don't happen.

There are two mindsets: try to work around problems to reach your goals, and try to come up with any problem to find excuses to not reach your goals. Complaining about naming sounds a lot like the second.

Re:Don't Be Afraid of Types by josephg on Saturday March 22, 2025 @04:05AM (#43444301)
> Don't all types need names, regardless of what language you use?

No.

- In very dynamic languages (like javascript), most types arguably don't have names at all. For example, I can make a function to add 2d vectors together. Even though I can use 2d vectors in my program, there doesn't have to be a 2d vector type. (Eg, const vecAdd = (a, b) => ({x: a.x+b.x, y: a.y+b.y}) ).

- Most modern languages have tuples. And tuples are usually anonymous. For example, in rust I could pass around 2d vectors by simply using tuples of (f64, f64). I can even give my implicit vector type functions via the trait system.

- In typescript you can have whole struct definitions be anonymous if you want to. Eg: const MyComponent(props: {x: number, y: string, ...}) {...}.

- There's also lots of types in languages like typescript and rust which are unfortunately impossible to name. For example, if I have this code:

    #[derive(Eq, PartialEq)]
    enum Color { Red, Green, Blue }

    fn foo(c: Color) {
        if c == Color::Red { return; }

        // What is the type of 'c' here?
    }
Arguably, c is a Color object. But actually, c must be either Color::Green or Color::Blue. The compiler understands this and uses it in lots of little ways. But unfortunately we can't actually name the restricted type in the program.

Rust can do the same thing with integers - even though (weirdly) it has no way to name an integer in a restricted range. For example, in this code the compiler knows that y must be less than 256 - so the if statement is always false, and it skips the if statement entirely:

https://rust.godbolt.org/z/3nTrabnYz

But - its impossible to write a function that takes as input an integer that must be within some arbitrary range.

Re:Don't Be Afraid of Types by relaxing on Saturday March 22, 2025 @07:32AM (#43445040)
The named integer range thing is interesting. I guess it depends on what you goal is. Could you use asserts? Could you wrap the integer in an object and embed the restriction logic there?
Re:Don't Be Afraid of Types by whilenot-dev on Saturday March 22, 2025 @08:04AM (#43445182)
Doable in TypeScript[0], but I'd wager if that's really necessary.

[0]: https://www.typescriptlang.org/play/?#code/C4TwDgpgBAogdgVwL... from StackOverflow[1]

[1]: https://stackoverflow.com/questions/39494689/is-it-possible-...

Re:Don't Be Afraid of Types by josephg on Saturday March 22, 2025 @09:17AM (#43445505)
> but I'd wager if that's really necessary.

I think its more useful in a language like rust, because the compiler can use that information to better optimize the emitted assembly.

Re:Don't Be Afraid of Types by whilenot-dev on Saturday March 22, 2025 @10:15AM (#43445742)
Even in compiled languages I think the benefits won't outweigh the difficulties in compiler optimization.

It starts with the question of how I would like to design my sequences:

- Is it the range (0, 10] in steps of 1?

- Is it the range (0, 2^10) in steps by the power of 2?

- Is it the range (0.0, 2PI] in steps of EPSILON?

How would the compiler engineer generalize this optimization?

And the question would continue whether I'd be really able to define them that precisely before runtime. Most applications are just dealing with lightweight structures, mostly serialized JSON nowadays, and then even there are enough fuck-ups[0] where such an optimization wouldn't help at all.

I can imagine the places where they really matter are some heavy memory intensive data structures like deep neural networks, graphics or video and the like - for the time being they're just dealing with tensors of data type floatX, and that seems to be fine AFAIK.

I mean, I'd be really nice if the smaller memory footprint could come out-of-the-box during compilation. But all the CLI tools written in rust certainly don't have the use case to put this complication on the shoulders of compiler research.

[0]: https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times...

Re:Don't Be Afraid of Types by josephg on Saturday March 22, 2025 @08:58AM (#43445419)
You could do it with asserts or as a wrapped type, but both of those approaches are only checked at runtime. That means you don’t get runtime errors instead of compiler errors. It also limits the compiler’s ability to take advantage of the constraint to optimise. Also asserts need to be added everywhere - by both you and the compiler. And wrapped types are annoying to use since you lose access to all the standard arithmetic operators.

It would be better if the type system could encode types like this directly. Better for ergonomics and better for optimisation.

Re:Don't Be Afraid of Types by whilenot-dev on Saturday March 22, 2025 @08:22AM (#43445252)
> Arguably, c is a Color object. But actually, c must be either Color::Green or Color::Blue. The compiler understands this and uses it in lots of little ways. But unfortunately we can't actually name the restricted type in the program.

I think that's less a question whether you can, but rather whether you should or shouldn't design it that way... (I'll use TypeScript here for the simpler syntax)

It'd be perfectly fine to do something like this:

  type ColorR = 'red';
  type ColorG = 'green';
  type ColorB = 'blue';
  
  type ColorRGB = ColorR | ColorG | ColorB;
But which constraint should your new type ColorGB (your variable c) adhere to?

  // constraint A
  type ColorGB = ColorG | ColorB;

  // constraint B
  type ColorGB = Exclude<ColorRGB, ColorR>;
I'd argue if the type ColorGB is only needed in the derived form from ColorRGB within a single scope, then just let the compiler do its control flow analysis, yes - it'll infer the type as constraint B.

But if you really need to reuse the type ColorGB (probably some categorization other than all the colors), then you'd need to pay close attention to your designed constraint.

Re:Don't Be Afraid of Types by josephg on Saturday March 22, 2025 @09:16AM (#43445501)
I really wish I could do in rust what you're doing here in typescript.

Say I have some enum like ColorRGB here. In some contexts, only a limited subset of variants are valid - say, ColorGB. There's a few ways to code this - but they're all - in different ways - horrible:

1. Use ColorRGB in all contexts. Use asserts or something to verify that the value is one of the expected variants. This fails at expressing what I want in the type system - and the code is longer, slower and more error prone as a result.

2. Have two enums, ColorRGB and ColorGB. ColorRGB is defined as enum ColorRGB { Red, Restricted(ColorGB) }. This lets me encode the constraint - since I can use ColorGB explicitly. But it makes Color harder to use - since I need to match out the inner value all over the place.

3. Have two enums, ColorRGB and ColorGB which both have variants for Green and Blue. Implement conversion methods (impl From) between the two types. Now I have two types instead of one. I have conversions between them. And I'll probably end up with duplicate methods & trait impls for ColorRGB and ColorGB.

Luckily this doesn't come up that often. But - as your typescript example shows - it can just be expressed directly in the type system. And LLVM already tracks which variants are possible throughout a function for optimisations' sake. I wish rust had a way to express something like Exclude<ColorRGB, ColorR>.

Re:Don't Be Afraid of Types by kirkhawley on Saturday March 22, 2025 @08:05PM (#43449733)
"Most modern languages have tuples. And tuples are usually anonymous." Sure! And I LOVE ending up with var names that are always Item1 and Item2... Very descriptive!
Re:Don't Be Afraid of Types by josephg on Sunday March 23, 2025 @05:52AM (#43451900)
Nobody’s saying anonymous tuples are necessarily a good idea. Just that lots of languages provide them.
Re:Don't Be Afraid of Types by gleenn on Saturday March 22, 2025 @03:02AM (#43444090)
All types don't need names exactly like the Clojure example shows. There is no "type" for the argument, likely it's a map under the hood. And maps with keywords are used broadly across Clojure projects as a method of pass groups of data and no, you don't have to name that arbitrary collection of data. Rich Hickey has an amazing presentation on the silliness of a commonly used Java Web Request library where the vast majority of object types required could have just been little nested maps instead of creating a ton of bespoke like types that make it difficult to assemble and manipulate all the bits. The interface he roasts could be completely discarded an nearly no benefits lost in terms of readability or usability. Hickey is also famous for saying he would rather a few data structures and a 100 little algorithms instead of 10 data structures and 10 algorithms per data structure.
Re:Don't Be Afraid of Types by Capricorn2481 on Sunday March 30, 2025 @04:13PM (#43527220)
> Hickey is also famous for saying he would rather a few data structures and a 100 little algorithms instead of 10 data structures and 10 algorithms per data structure

This is a quote from Alan J. Perlis, not Rich Hickey, and it's certainly not what Rich is famous for.

Re:Don't Be Afraid of Types by noduerme on Saturday March 22, 2025 @02:57AM (#43444070)
I think Java culture had something to do with the ridiculously verbose names, but even more so the prevalence of Factory and Singleton paradigms in Java created these issues. Maybe because it was the first OO language that a lot of procedural coders came to in the 90s. Those patterns became sort of escape hatches to avoid reasoning about ownership, inheritance and scope. They're still common patterns for emergencies in a lot of ECMA-whatever languages resembling Java: You need a static generator that doesn't own the thing it instantiated, and sometimes you only need one static object itself... but one reaches for those tools only as a last resort. After thinking through what other ways you could structure your code. The super-long-name thing in Java always felt to me like people trying to write GOTO/GOSUB type procedural programs in an OO language.
Re:Don't Be Afraid of Types by motorest on Saturday March 22, 2025 @03:25AM (#43444163)
> I think Java culture had something to do with the ridiculously verbose names, but even more so the prevalence of Factory and Singleton paradigms in Java created these issues.

It sounds like you're confusing things. Factories are a way to instantiate objects of a specific type a certain way. Singletons is just a restriction on how many instances of a type there can be.

These are not Java concepts, nor are they relevant to the topic of declaring and naming types.

Re:Don't Be Afraid of Types by bluGill on Saturday March 22, 2025 @10:52AM (#43446067)
They are not Java concepts, but abusing them by using in contexts where they are a bad answer is something Java tends to take to the limit. (I fight the same abuse in C++, and it always seems that Java "best practices" is where the idea came from)
Re:Don't Be Afraid of Types by pjmlp on Saturday March 22, 2025 @03:10AM (#43444126)
For whatever reason Java gets the blame for what was already common Smalltalk, C++, Clipper 5, Object Pascal, Actor, Eiffel, Objective-C,....before Oak idea turned into Java.

To the point many think the famous patterns book used Java, when it is all about Smalltalk and C++ patterns.

Re:Don't Be Afraid of Types by motorest on Saturday March 22, 2025 @03:28AM (#43444174)
> For whatever reason Java gets the blame for what was already common (...)

Java's problem is that it's hugely successful, and to some it's the only language they ever experience in their formative years. Thus, because poor workmen always blames the tools, Java becomes the root of all evil.

Re:Don't Be Afraid of Types by pjmlp on Saturday March 22, 2025 @04:01AM (#43444285)
That and the historical illiteracy the industry suffers from.
Re:Don't Be Afraid of Types by re-thc on Saturday March 22, 2025 @03:21AM (#43444149)
> I think Java culture had something to do with the ridiculously verbose names

People complain about this all the time but I'd rather take a verbose name than not knowing what is going on. Sometimes these naming conventions help.

Digging into older poorly named, structured and documented codebases is not fun.

Re:Don't Be Afraid of Types by noduerme on Saturday March 22, 2025 @03:28AM (#43444171)
Definitely. If you have functions that only do one thing and are only called a few other place in the code, then by all means, name them explicitly. And I'd rather see that than a bunch of the same inlined anonymous function. I'm not really knocking the naming patterns as much as the data/logic patterns that required them. Factories are not a good thing. They usually imply that globals need to hold references. Obviously, so do Singletons. Global lifecycles in general are just easy to create and really hard to manage on your own.

Good comments are better than good function names.

Re:Don't Be Afraid of Types by motorest on Saturday March 22, 2025 @03:47AM (#43444226)
> Factories are not a good thing. They usually imply that globals need to hold references.

No. Your statements are fundamentally wrong at many levels. Factories are tools to instantiate objects of a specific type a certain way. They are constructors that don't suffer from the limitations of constructors. A factory does not impose any requirement on object life cycle.

Re:Don't Be Afraid of Types by lurking_swe on Saturday March 22, 2025 @04:37AM (#43444382)
correct. i chuckle when someone talks so authoritatively on a topic they didn’t try to fully understand in the first place.
Re:Don't Be Afraid of Types by noduerme on Saturday March 22, 2025 @05:53AM (#43444611)
How you use a factory matters. A factory that sits as a static function inside the same class it's creating is one thing. It may just be a nicer interface to instantiate the class than the constructor itself.

On the other hand, it may do something with the object it's instantiating before passing it back. Such as putting it into global scope, or tying it to something outside its chain. Factories that sit outside the class file are often prone to all kinds of grotesque later mucking-with that causes the instantiated object to bind to other scope, and never be properly garbage collected. That's what I'm talking about.

Build better constructors and you won't usually need factories. If you need factories as an API, build them next to the constructor.

Re:Don't Be Afraid of Types by peterashford on Monday March 24, 2025 @11:58PM (#43468005)
tbf those are features of early Java frameworks (particularly the awful java enterprise crap)
Re:Don't Be Afraid of Types by jayd16 on Saturday March 22, 2025 @02:49AM (#43444032)
C# has anonymous types, for example. Kind of like tuples but you can name the fields.
Re:Don't Be Afraid of Types by jandrewrogers on Saturday March 22, 2025 @03:02AM (#43444089)
Anonymous types are a thing in some languages. You also have adjacent concepts like anonymous namespaces in which you can dump types that require a name so that the names don’t leak out of the local context.

Sufficiently flexible namespaces do solve most of these problems. Java is kind of perverse though.

Re:Don't Be Afraid of Types by gleenn on Saturday March 22, 2025 @03:04AM (#43444100)
Java:

Map m = new HashMap() {{ System.out.println("I am a unique subclass of HashMap with a single instance!");}};

Re:Don't Be Afraid of Types by GrantMoyer on Saturday March 22, 2025 @10:01AM (#43445684)
The types of closures are unnamable in C++ and Rust; each closure has a unique type that can't be written out. Function types (that is, "function item" types) in Rust are also unnamable.
Re:Don't Be Afraid of Types by marcosdumay on Saturday March 22, 2025 @12:46PM (#43446975)
You kind of answered your question, didn't you?

Because the types in typescript don't need names. And the type "object with firstName and lastName" is one such type that doesn't need a name.

So:

> They don't seem to have a problem with names.

Yes. The problem is much smaller there, and mostly caused by programmer cultures that insist on naming everything.

Re:Don't Be Afraid of Types by dharmab on Sunday March 23, 2025 @12:14AM (#43450870)
I frequently use anonymous types in my unit tests in Go. I create a custom type describing the inputs, behaviors and expected outputs of a test case. I create a collection of these cases, and use Go's standard library testing package to run the test cases concurrently scaling to the CPU's available threads.

Here's a simple example: https://github.com/dharmab/skyeye/blob/main/pkg/bearings/bea...