[idea] foo !: Bar - type conversion operator

So, how about :! and :? instead?

meaning:

: : The left IS the right. (blame me if not)

:! : The left Need to be the right ! (just DO IT, I dare panic)

:? : May the left be the right ? (tell me the answer, I want to be safe)

2 Likes

I still believe ! as into, with corresponding T->into->Result<T, E> and T->into->Option<T> and all the other stuff I mentioned, is the way to go.

(if only you could do A/B testing with the compiler…)

I agree that using the exclamation point to mean "I dare panic" is a very appealing idea. Long time ago there was a proposal to make this happen (macro would have used @). I really think it would have been great.

But it's far too late to go that way now. The ! means macro expansion when it is used as a suffix and it means negation when it is used as a prefix. It's already too much for my taste, I don't want to overload the exclamation mark with another meaning.

While I think that having a clean syntax for conversion is a desirable goal, using the exclamation mark for that purpose seems very odd to me. I think we can spare visual complexity if we choose to fix the current as operator instead of just replacing it.

I guess it can be done in a way compatible with the edition system. The as operator would use conversion trait first. If no trait is found, it would behave the old way and rise a warning (In the current edition). In future editions it would be a error.

Can we transform as to a sugar for From, by deprecating some of the current functionality? (though I think things like creation of trait objects and pointer casts will have to be special cased) This way we will be able to use as? for TryFrom.

2 Likes

I’m not sure it’s possible but I believe it worth to investigate this path before introducing a new operator. I did not proposed the as? at first to keep it simple, but I was thinking about this too.

I don’t believe TryFrom should be a property of the type. Same way I expect to use Wrapping(v) !: Foo.

In any case, ! as an operator adds ergonomics for fallible functions. Never write Some(v) or Ok(v) again, just write v! and it’ll automatically work for both the Result and the Option kind of function.

Incidentally, Wrapping(v) !: Foo makes it look like you’re trying to specify that Wrapping(v) will not be a Foo.

3 Likes

it’s Wrapping(v)-into-a-Foo. just like type ascription is read v-a-Foo.

This isn’t negative type bounds foo: !Foo.

You don’t have to teach me what it means, you have to have the syntax teach the people who are not in this forum what it means. I say it looks like a negative type bound because if you weren’t here to explain what it does, I would assume it is some kind of negative type bound. The difference between !: and :! is not great enough to make me assume they mean wildly different things.

I believe this is a general problem with trying to use ! as a conversion signal consider the differences between the following two situations:

let y = true;
let x: bool = !y;
let y = true;
let x: bool = y!;
2 Likes

What about foo! : Foo

If we’re still in the business of bikeshedding symbol combinations for the proposed operator, I’ll throw a new one in: :>. This symbol, and variants of it, have some precedent as a subtyping operator in other programming languages.

So foo> for into and foo >: Bar for into-a-Bar?

(such that Result and Option functions both use ? and > in the same places - bringing them closer together syntactically)

Note: This operator is usually written in reverse, T <: S meaning "T is a subtype of S", for example: 'b <: 'a ⊢ &'b u8 <: &'a u8.

It would probably have to be :>, not >:, otherwise you run into ambiguity with < and >:

let x: bool = a < b >: bool;

There’s no ambiguity there.

Is it

let x: bool = (a < b) >: bool;

or

let x: bool = (a < b >): bool;

The latter. > happens first, just like a < b.into().

Remember that ‘> not followed by an identifier/value/expression’ means ‘into’, and the type ascription operator is none of those.

On second thought, the latter doesn’t make much sense unless ::<> is removed… so maybe there is no ambiguity after all. (Aside from precedence, of course.) Though we’d still be enabling wacky things like a < (b::c < d >: e)

EDIT: Using > as an infix operator, bracketting symbol, and postfix operator is pretty crazy. Here’s another potential ambiguity: a >> b. Is it a.into() > b or a.shr(b)?

>> is longer than > so it parses first (it should be greedy). a > > b is a.into() > b

(and this is where I say ! would be better)

Just because you have a way to resolve an ambiguity doesn’t mean the ambiguity doesn’t exist. It means you have to do real work to understand the code. I’m pointing out these ambiguities not because we need to come up with a way to resolve them, but because we need to understand what will happen when a user types that code. They’re going to expect one thing to happen, and instead get something entirely different – perhaps it silently works and gives confusing results, or perhaps it gives a cryptic error that has nothing to do with what they thought they were doing. (The former being far worse.)

It is not hard to resolve ambiguities – It’s hard to do it in a way that doesn’t frustrate people.

4 Likes