Stream: beginners

Topic: ✔ difference between `List *` and `List _`


view this post on Zulip Anton (Jun 14 2024 at 16:01):

In reply to this message. In List _, _ is a type hole, the compiler will fill this in itself using type inference. You could use List _ as follows:

strList : List _
strList = ["abc", "def"]

numList : List _
numList = [1, 2, 3]

If we use List * we do define a type ourselves; e.g. lst : List * could only be lst = [].

view this post on Zulip Akeshihiro (Jun 14 2024 at 17:14):

So the * is somewhat similar to the void type in other languages? So one may prevent of using other types, like in combination with the Task type with Task Str * to say that there is no effect allowed in the function?

view this post on Zulip Anton (Jun 14 2024 at 17:57):

So the * is somewhat similar to the void type in other languages?

In some cases (like Task Str *), it is similar, but when it is used for a function argument e.g. List.isEmpty : List * -> Bool, it is not like void at all because here it means a list of any type (List Str, List U64...).

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 19:09):

It still is functionally a void type there. You have a list of what might as well be void cause you can't interact with the elements

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 19:09):

You still can get the length though

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 19:09):

Cause that doesn't depend on the element type

view this post on Zulip Akeshihiro (Jun 17 2024 at 04:55):

Thank you, I think I'm getting it now. At first i thought that both, the _ and the * were some sort of generics placeholders. But after some tinkering it seems that the _ is really only a placeholder for the type the compiler will figure out and fill in, which may be a generic type and even the * if needed. That's why it is called type hole. But the * is actually a generic type, but says more specific to the reader that the type is ignored and not used, at least in the case of a container type like List *, where one wants to operate on the list itself but without using the actual elements, like for example when calculating the list's size as here the actual element's type doesn't matter. With a List a one might think that the type is important whereas in List * it is clear that the element's type isn't used and therefore doesn't matter. So it is more explicit. So the * can be seen as something like any or object types in other languages I think.

view this post on Zulip Brendan Hansknecht (Jun 17 2024 at 05:44):

That is a good summary with the caveat that any and object types generally have some form of runtime reflection that can allow you to convert them to other types and interact with them. Roc has no such infrastructure. You simply can't interact with an element type that is *.

view this post on Zulip Akeshihiro (Jun 17 2024 at 07:01):

Thanks for the clarification. But I must say that I see such type definitions more like a contract. So even in languages like C# or Java, when a method consumes an interface type object or returns an interface type object, what I care about is the functionality that the interface offers me. But yeah, I've seen a lot of code from other people like my coworkers who cast the interface type objects to other types because they know which type it really is so that they are able to call methods not provided by interface. And when the concrete type gets swapped out everything crashes at runtime and we have to fix. A really awful place to be in, so I tend to see types more like a contract which allow me to do something with the object behind. If the given type does not offer the requested operations, then I have to refactor something.

view this post on Zulip Akeshihiro (Jun 17 2024 at 07:02):

But then I think the question has been answered, so I'll mark the topic as resolved. Thank you guys!

view this post on Zulip Notification Bot (Jun 17 2024 at 07:04):

Akeshihiro has marked this topic as resolved.

view this post on Zulip Brendan Hansknecht (Jun 17 2024 at 15:23):

And when the concrete type gets swapped out everything crashes at runtime and we have to fix.

Yeah, have definitely seen that before.


Last updated: Jul 06 2025 at 12:14 UTC