In which situation are IntLiteral, FloatLiteral, StringLiteral useful?

I know those refer to the type use by the compiler, and they mean that they are compile time constant. But it seems to interfer with the alias/var distinction. The constness isn't really clear here. It seems to me that those type are just compiler implementation details. If we use alias and that the compiler cast automatically IntLiteral to Int, FloatLiteral to Float and StringLiteral to String, we don't loose anything (since those can be used in compile-time with alias), or am I missing something? If those types are not useful in the language, should we remove them? In all my programs, I always cast them to the conrresponding runtime types, even if the value is known at compile time. I guess the more general question is "in which situations is the decorator @nonmaterializable https://docs.modular.com/mojo/manual/decorators/nonmaterializable.html useful?"
25 Replies
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
For example, with automatic and immediate casting, those errors wouldn't happen: https://github.com/modularml/mojo/issues/1595
GitHub
[BUG]: IntLiteral's __iadd__ etc. methods doesn't work in (dyna...
Bug description As title. Maybe it's the intended semantics (IntLiteral needs to be materialised at compile time), the error message could still use some improvements. Steps to reproduce Consid...
a2svior
a2svior12mo ago
I noticed that e.g. some imported Python functions work with StringLiteral but not with String
sora
sora12mo ago
They give types to literals, capture them lossless ways, and contain logic like fromIntegral in Haskell. They also provide e.g. overflow checks in a non magical way (not hard coded into the compiler).
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
For overflow check we could have something like that:
struct Int:
fn __add__(self, other):
if is_compile_time():
return safe_add(self, other)
else:
return unsafe_add(self, other)
struct Int:
fn __add__(self, other):
if is_compile_time():
return safe_add(self, other)
else:
return unsafe_add(self, other)
sora
sora12mo ago
I think they would at least in principle provide a way to cast from FloatLiteral to some low precision float type without going through f64. No I meant from literal to int Int(some large literal) errors out and where do you put the check? What is between the parenthesis anyways without some form of literal type
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
Can we have a materialized type called InfiniteAndSafeInt and then use that instead?
sora
sora12mo ago
Then we are not removing the literal types aren’t we? If your problem with them is that they are not materialisable, and don’t have the expected runtime behaviour then I agree. Maybe they shouldn’t be exported by default. I’m on my phone so I will use overly simplified words. I THINK the mojo group is trying very hard to not provide a is_compile_time. It’s all my speculation though.
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
This can actually be useful to add safeties when running at compile time.
sora
sora12mo ago
I think having phase control (moving computations to compile time) and being able to branch on phase are different things. is_compile_time can easily be used for the latter, which (I think) is pretty bad)
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
Maybe I'm just having this position because right now Int is unsafe because it's possible to overflow. If in the future it's safe at runtime, it's quite likely my argument won't stand anymore
sora
sora12mo ago
Ah, so you want safety in constant folding?
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
I would just expect that this code is safe:
fn big_number() -> Int:
var a = 2**60
var b = 2**60
return a * b
alias c: Int = big_number()
fn big_number() -> Int:
var a = 2**60
var b = 2**60
return a * b
alias c: Int = big_number()
Everything runs at compile time in this example, we can affort a few checks and thus raising an error at compile-time
sora
sora12mo ago
I guess when overflow traps at runtime, your problem will go away.
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
Indeed, that's what I hope are there known differences between FloatLiteral and Float btw? Same for String? The docs doesn't mention differences. If they have the same behavior and data, maybe we could have auto cast too for those? Sorry for the questions, maybe I should just wait for the standard library to be open source haha
sora
sora12mo ago
I think you could just write feature requests and bug reports if you find the behaviour or documentation needs improvements (which I agree).
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
What incited this discussion is this issue: https://github.com/modularml/mojo/issues/1595 and I was very lost (it seems even the modular staff doesn't agree on the desired behavior), so I'm not sure how beginners can understand what is going on, when even me as an experienced programmer, can't wrap my head around it. And IntLiteral is the very first type users work with, so they have to understand what is going on... I often forget to cast StringLiteral to String for example, and I get error messages saying that StringLiteral isn't mutable, etc. So as a beginner, one must understand StringLiteral AND Strings, which is a lot of complexity I believe for someone who starts
a2svior
a2svior12mo ago
Also I think it's not possible to cast back from String into a StringLiteral
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
The progressive disclosure of complexity isn't really a thing here Yes indeed. But it should be possible if running at compile-time, in theory.
fn some_str() -> String:
return "hello"
alias a: StringLiteral = some_str()
fn some_str() -> String:
return "hello"
alias a: StringLiteral = some_str()
This should work. I'll try it (but I don't see why anyone would want to do this)
a2svior
a2svior12mo ago
For me specifically this was a problem because some imported Python functions can apparently expect a StringLiteral and break with Strings, and if I just had a String I had to find workarounds
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
Doesn't work:
/projects/open_source/mojo-stdlib-extensions/trying_stuff.mojo:4:34: error: cannot implicitly convert 'String' value to 'StringLiteral' in alias initializer
alias a: StringLiteral = some_str()
~~~~~~~~^~
mojo: error: failed to parse the provided Mojo
/projects/open_source/mojo-stdlib-extensions/trying_stuff.mojo:4:34: error: cannot implicitly convert 'String' value to 'StringLiteral' in alias initializer
alias a: StringLiteral = some_str()
~~~~~~~~^~
mojo: error: failed to parse the provided Mojo
I don't know if it's the desired behavior....
a2svior
a2svior12mo ago
I think that's what I was getting too. Also not sure if it's on purpose, maybe literals are not meant to be created like this
gabrieldemarmiesse
gabrieldemarmiesseOP12mo ago
I wonder what StringLiteral can do that String can't...
sora
sora12mo ago
This I don't agree. StringLiteral is a type that's compile time only, and String is a type that can be evaluated at compile time, and that's an important distinction to be made at type level (what @nonmaterializable means). Some form of StringLiteral (same for other literal types) is not avoidable, for they capture the transition from tokens in the source code to typed values in the language. In the case of String, I'm not sure the String("...") thing is gonna go away (think rust, this is inherent complexity to system programming), maybe they should auto promote to borrow checked StringView which we don't have. I think why Mojo developers hold different views in my issue there because the problem is not that easy to answer. My interpretation of the problem boils down to this question: Should compile time only values allowed in dynamic control structures that are not really dynamic (the loop is really a bounded loop that terminates)?
gryznar
gryznar12mo ago
According to Modular, StringLiteral should be also promoted automatically to String and it is reported issue somewhere It is mentioned in the roadmap / sharp edges. Int will be protected
gryznar
gryznar12mo ago
https://docs.modular.com/mojo/roadmap.html#the-standard-library-has-limited-exceptions-use It is mentioned here. Not directly, but overflow seems to be the same type as division by 0
Modular Docs - Mojo🔥 roadmap & sharp edges
A summary of our Mojo plans, including upcoming features and things we need to fix.
Want results from more Discord servers?
Add your server