Is there a way in Mojo to know the type of a variable/object ?

Something like type() in Python. If not, is this useful and/or on the roadmap?
55 Replies
Ryulord
Ryulord2mo ago
No but it's very rare you'd need something like that since all types are known at compile time. Can you describe your use case? There's probably a way to do what you want to do.
Ivo Balbaert
Ivo BalbaertOP2mo ago
Thanks. Are types then not known (thrown away) at runtime?
Melody Daniel
Melody Daniel2mo ago
I imagine this is useful as Mojo gets more dynamic. type(), isinstance(), issubclass(), and other runtime reflection capabilities will be added, they're crucial for writing any meaningful dynamic program
Darkmatter
Darkmatter2mo ago
Runtime type information is one of the most famous mistakes of C++, so there will be a very long discussion about how necessary that is.
Melody Daniel
Melody Daniel2mo ago
I don't expect there'll be a long conversation at all. You need runtime reflection if you're going to have dynamism
Darkmatter
Darkmatter2mo ago
You don’t, you just make sure your types quack like a duck (correctly named functions and the correct members). All of that is pure hash table lookups, no runtime type information.
Melody Daniel
Melody Daniel2mo ago
I'm not sure I know what you mean. There are cases where your expected input can be any number of different types You have to reject types that don't fit without crashing the problem
Darkmatter
Darkmatter2mo ago
If the type looks like it satisfies the interface you need, you accept it. If the user passed in an incorrect type that’s their problem. That’s the trade-off of dynamic languages, it’s easier to write libraries because the user is responsible for passing in the right types, and you can have a stack trace from deep in your library if they are wrong.
Melody Daniel
Melody Daniel2mo ago
Like I said. There are cases where your expected input can be different types
Darkmatter
Darkmatter2mo ago
So you check if it looks like one of them.
Melody Daniel
Melody Daniel2mo ago
How would you do that?
Darkmatter
Darkmatter2mo ago
Lots of “contains”. Dynamic types are sparkling hash tables.
Melody Daniel
Melody Daniel2mo ago
Are you talking about implementation details here? I wouldn't want to be overcomplicating things for scenarios that would take a just a few characters
Darkmatter
Darkmatter2mo ago
The other option is something which only works in dynamic areas of the language, or a function which is conditionally comptime based on the inputs. Part of the contract of dynamic languages is that you document “I accept these types”, and then the user gets a stack trace if they mess it up.
Melody Daniel
Melody Daniel2mo ago
I'm still not sure we're talking about the same things. Like I've said before, I'm a fan of everybody having responsibilities
Darkmatter
Darkmatter2mo ago
If you want nice type errors, use a statically typed language. The whole point of duck typing is that “close enough” works. Using typeof defeats that.
Melody Daniel
Melody Daniel2mo ago
But it is common in dynamic languages to expect an input of different types, and then check at runtime what type you got and process the input differently
Darkmatter
Darkmatter2mo ago
Yes, but you shouldn’t use typeof, you should be checking if there’s an index operator, a len function, etc. That’s the whole point of duck typing, and why you can pass numpy arrays into many things that expect a list.
Darkmatter
Darkmatter2mo ago
If you keep detailed type information around at runtime, there are costs. https://www.sandordargo.com/blog/2023/03/01/binary-sizes-and-rtti
Sandor Dargo’s Blog
Binary sizes and RTTI
What is RTTI? What does it have to do with the size of your executables? Let’s start with answering the first one. RTTI stands for run-time type information. It’s available for every class that has at least one virtual function. With the help of such information, you can determine the type of an object during execution and use it for different p...
Melody Daniel
Melody Daniel2mo ago
And in a language like Python abstract base classes are heavily used for things like this. so you would do: if issubclass(input, abc.Sequence)
Darkmatter
Darkmatter2mo ago
But, since you can only inherit from a single base class, you’ve just limited the users of your API to types which have a free base class slot. If you instead checked for something which quacks like an abc.Sequence, you would be able to accept a lot more types.
Melody Daniel
Melody Daniel2mo ago
How would you check that? like, an example
Darkmatter
Darkmatter2mo ago
You check for len, getitem, and next. That the functions which make up that API contract exist.
Melody Daniel
Melody Daniel2mo ago
in the object's dir namespace?
Darkmatter
Darkmatter2mo ago
You can check via dict(obj). Or other ways like getattr.
Melody Daniel
Melody Daniel2mo ago
ah. I'm sure both are useful at different times
Darkmatter
Darkmatter2mo ago
dict doesn’t work on things which are dict-like. So getattr is technically more portable.
Melody Daniel
Melody Daniel2mo ago
technically. If I expect you to pass a subclass of some custom ABC or another. issubclass works better, I intended to limit my API
Darkmatter
Darkmatter2mo ago
What you typically do is write one of these functions per “trait”. That’s great until I’m in an enterprise codebase and can’t use your library because you were more specific with the API than you had to be. “Be liberal in what you accept and conservative in what you emit” -Joe Armstrong If you follow that advice, it can save a lot of headache later on.
Melody Daniel
Melody Daniel2mo ago
I'm sure it can. However, I'm already being liberal with what I accept by accepting an ABC On ABCs, Protocols has been introduced to make the type checking more structural.
Darkmatter
Darkmatter2mo ago
Protocols and abcs are different You can only have 1 ABC, which becomes a problem if lots of libraries use them.
Melody Daniel
Melody Daniel2mo ago
Checking what attributes an object has at runtime is also runtime reflection btw It doesn't really matter for my point. Which is that in many cases I need a way to check if a type matches a set of type that I want at runtime.
Darkmatter
Darkmatter2mo ago
What we can probably do later on is have a “quacks_like” function which checks if a type looks like it implements a trait.
Melody Daniel
Melody Daniel2mo ago
A trait is a compile time functionality. Why does it require extra checking? The compiler will reject any object that doesn't For dynamic stuff. We don't need to reinvent the wheel or overcomplicate things here. In fact, I believe one of the main reasons for basing Mojo on Python is to avoid bike shedding like this on functionalities that have been fixed for 30 years
Darkmatter
Darkmatter2mo ago
The compiler has no way of knowing what an object looks like at compile time. It could have been read from a pickle file that someone manually edited in a hex editor. So, if we want traits to work on object, there needs to be a runtime check. People have been arguing about composition vs inheritance for longer than that.
Melody Daniel
Melody Daniel2mo ago
Not from where I'm looking at it. If you have, for example, a class with a method that expects a trait, The method's signature stops being object. Typescript works this way. Oh, I think I see where you're coming. In the case where the input is coming from an unknown source then the type should be "unknown".
Darkmatter
Darkmatter2mo ago
In that case, almost the entire standard library is inaccessible to def functions. Binary types need to be parsed as something. The most likely return type of something that reads arbitrary JSON is object. Systems languages don't get to have an "unknown" type unless you mean OpaquePointer.
Melody Daniel
Melody Daniel2mo ago
It does?
Darkmatter
Darkmatter2mo ago
Yes, standard library functions are written entirely in fn, there needs to be a way to bridge that gap.
Melody Daniel
Melody Daniel2mo ago
It seems unknown isn't very widespread. For some reason it is supported by Pyright but not Mypy. Yeah I see what you mean We need a form of any
Darkmatter
Darkmatter2mo ago
unknown as a type cannot exist in Mojo. OpaquePointer is as close as you can get. There is no guarantee of any kind of layout, no way to discover what functions exist. If you do that with RTTI, you make every integer carry a pointer around with it.
Pun
Pun2mo ago
There's no such thing as an unknown type In typed languages unknowns is just an integer, or byte, or any other direct bit representation
Melody Daniel
Melody Daniel2mo ago
Typescript has a concept of unknown type. Once place where it is useful is when creating a http client, you could make the type of response body unknown. Requiring the library consumer to fill it in
Pun
Pun2mo ago
It's just bits though
Melody Daniel
Melody Daniel2mo ago
The difference between any and unknown is that you can't pass unknown to any function without explicitly casting it to a concrete type
Darkmatter
Darkmatter2mo ago
Typescript runs in a sandbox where every type can reliably be treated like a hash table. Mojo does not, if you try to do that you will crash your program.
Pun
Pun2mo ago
In theory a pointer can point to bits you don't know how to interpret Thus making it an "unknown" type Then at runtime you can try casting those bits into types and see what happens
Melody Daniel
Melody Daniel2mo ago
Unknown types actually needs to be casted to known types at compile time
Pun
Pun2mo ago
Nope, because they were always a type They were bits
Melody Daniel
Melody Daniel2mo ago
I'm not talking about data here. Just data type. Since this concept doesn't exist almost anywhere else I have to imagine it is not very useful Tbh, it is not all that useful
ModularBot
ModularBot2mo ago
Congrats @Melody Daniel, you just advanced to level 20!
Melody Daniel
Melody Daniel2mo ago
Proper generics is possibly what you want in almost every case where you may need it
Darkmatter
Darkmatter2mo ago
any and unknown exist because TS needed JS interop.
Pun
Pun2mo ago
It exist in lots of places, usually unknown it is called object
Darkmatter
Darkmatter2mo ago
What languages?

Did you find this page helpful?