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
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.
Thanks. Are types then not known (thrown away) at runtime?
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
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.
I don't expect there'll be a long conversation at all. You need runtime reflection if you're going to have dynamism
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.
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
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.
Like I said. There are cases where your expected input can be different types
So you check if it looks like one of them.
How would you do that?
Lots of “contains”.
Dynamic types are sparkling hash tables.
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
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.
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
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.
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
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.
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...
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)
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.
How would you check that?
like, an example
You check for len, getitem, and next.
That the functions which make up that API contract exist.
in the object's dir namespace?
You can check via dict(obj).
Or other ways like getattr.
ah. I'm sure both are useful at different times
dict doesn’t work on things which are dict-like.
So getattr is technically more portable.
technically. If I expect you to pass a subclass of some custom ABC or another. issubclass works better, I intended to limit my API
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.
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.
Protocols and abcs are different
You can only have 1 ABC, which becomes a problem if lots of libraries use them.
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.
What we can probably do later on is have a “quacks_like” function which checks if a type looks like it implements a trait.
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
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.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".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
.It does?
Yes, standard library functions are written entirely in
fn
, there needs to be a way to bridge that gap.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
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.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
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
It's just bits though
The difference between
any
and unknown
is that you can't pass unknown to any function without explicitly casting it to a concrete typeTypescript 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.
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
Unknown types actually needs to be casted to known types at compile time
Nope, because they were always a type
They were bits
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
Congrats @Melody Daniel, you just advanced to level 20!
Proper generics is possibly what you want in almost every case where you may need it
any
and unknown
exist because TS needed JS interop.It exist in lots of places, usually unknown it is called object
What languages?