Optional string argument

Is there a simple way to create a function that takes an optional String argument with no default value (assigned to None) ? I tried the following:
fn my_func(my_string: Optional[String] = None)-> String:
...
fn my_func(my_string: Optional[String] = None)-> String:
...
this works for a String but calling the function with a StringLiteral does not: my_func("my_string") gives the following error invalid call to 'my_func': argument #0 cannot be converted from 'StringLiteral' to 'Optional[String]' I guess one way to make it work for now is to use a default value as follows:
fn my_func(my_string: String = "my_default_string")-> String:
...
fn my_func(my_string: String = "my_default_string")-> String:
...
But this does not allow to distinguish between a bad input and an empty imput
10 Replies
artemiogr97
artemiogr974mo ago
btw, I would like to have several arguments being optional so defining several overloads could be complicated
Hammad Ali
Hammad Ali4mo ago
The problem is with String and stringLiteral. You ought to convert your stringLiteral ("my_string") to a standard string
artemiogr97
artemiogr974mo ago
yeah, I know that i can call String("my_string"), I was just wondering if it was possible to prevent doing that when using Optional, the same way you don't have to call String when the type is simply String I guess at some point mojo is going to be able to know that is is possible to transform StringLiteralto Optional[String]?
Nick!
Nick!4mo ago
The reason your program is rejected is that multiple conversion steps are required to get from a StringLiteral to an Optional[String]. Mojo is unlikely to ever support a multi-step chain of implicit conversions, so the question is ultimately whether there is a principled way to move between the two types via a single conversation step. The constructor for Optional obviously cannot accept a StringLiteral or a Stringable because Optional isn't necessarily parameterized by the type String, but perhaps at some point there will be a principled way to add a constructor overload for Optional[String] in particular. (This can be achieved via Swift-style "extension methods".)
benny
benny4mo ago
what about my_string: String = "" where "" is a value recognized as None? alternatively, if you want to accept "" as a valid input, you could just replace this with some nullish value like "NULL_STRING"
artemiogr97
artemiogr974mo ago
Yep, at the end I found some values that made sense for my case, so I just defined some defaults for everything I was just wandering if it was possible to keep my python code as it was, every argument was Optional[str]=None
sora
sora4mo ago
Unlike in python, you should think hard on if your function should take an optional. If you simply what to have a default argument, you could create an overload.
benny
benny4mo ago
you could also try Option[Stringable] not sure if that works though
artemiogr97
artemiogr974mo ago
it's not the same, a Float is Stingable, but I don't want to take floats as inputs I guess so, and I can tell you that as someone that's been developing in python for a while. I really appreciate having "real" overloads, I no longer have to write def my_fun(arg: Type1| Type2):... and handle everything in one function, I can simply write 2 overloads and treat each case separately, but then again converting from StringLiteral to Optional[String] seem like something that should be doable at some point (I don't necessarily say that would be easy to implement for mojo)
sora
sora4mo ago
Yea. In Python, None as default argument is actually one of the three cases: 1. Function that really takes a Optional[T] 2. Use None to work around mutable default argument (e.g. []) 3. Use None as placeholder for a more complex or private default argument (e.g. a default lambda) Only the first case should map to a function that takes an optional. 2 maps to simply function with default argument and 3 maps to proper overloads. As for StringLiteral to Optional[String], I don't think it's that much of a problem. When we have language level enum, it will look like .some("string") anyways.