try this Lua code: print(1..0)
and then print(1 .. 0)
Do you have a point, or are you just assigning arbitrary homework?
it’s a small ambiguity in Lua. the former errors because 1. is a float.
we (rust) have a similar ambiguity with 1.max(0), 1..max(0) (this doesn’t do what you think it does), 1. .max(0), etc.
Swift has as!
and as?
operators.
For Rust it would make sense to map as?
to TryFrom
. However, it looks questionable with the try operator:
let bar = (foo as? Bar)?;
this is why I don’t believe in TryFrom as a trait/operator/operation.
it should be impl From<TryFrom<T>> for Option<U>
, IMO. Optionally through a convenience trait so you don’t have to write it like this.
Interesting, probably stupid idea spitball:
name as? Type
desugars to TryFrom::try_from(name)?: Type
(where :
is type ascription here, and ?
is still error bubbling)
No, not stupid. That's interesting! and is worth investigation.
Not stupid at all. Actually, I believed it was how everyone expected the as?
operator to work.
Others come up with as?
idea as well (including me ). The main problem IIUC is how to deprecate some of the current as
behaviour (e.g. f32 -> u32
casts, pointer casts, etc.), so it indeed will become a sugar around From
.
I believe the answer will need to be "Edition 2021" if we want to do that.
The as
operator isn't very loved anyways and probably doesn't deserve to be an operator (i.e. should be relegated to a trait...).
I mean we will need set of language intrinsics to handle conversions which are currently offloaded to as
. (IIRC it’s currently impossible to convert f32
to u32
other than via as
) BTW I am not sure if we indeed need full set of traits to describe all possible classes of conversions in the std. I think they can be first added to num-traits
(or similar crate) to mature and implementations will use aforementioned intrinsics.
We don’t need more traits. From is all we need. If you think we need more, you’re doing it wrong.
Wrapping (256u16).into(): u8 == 0u8
256u16.into(): Option<u8> == None
These are simple IMO.
I’ve wanted something like this several times - it seems like some points in this thread have veered towards a fallible casting operator; my favorite mentioned syntax so far was as?
.
Specifically, here’s one incarnation of something I’ve encountered many times (it usually involves enums, especially &str -> Enum, but there are plenty of other variants (excuse the pun) exhibiting a fallible cast/conversion like operation):
#[repr(usize)]
#[derive(Debug)]
pub enum Normal {
North = 0,
South = 1,
West = 2,
East = 3,
Up = 4,
Down = 5,
}
impl Normal {
// I want to implement a trait so I and my clients
// don't have to memorize another random function name
pub fn from_idx(idx: usize) -> Option<Self> {
use self::Normal::*;
match idx {
0 => Some(North),
1 => Some(South),
2 => Some(West),
3 => Some(East),
4 => Some(Up),
5 => Some(Down),
_ => None,
}
}
}
fn main() -> Result<(), Error> {
let i = 3;
// i want to write this for the fallible cast/conversion
let n = i as? Normal;
// always safe
let i2 = n as usize;
assert_eq!(i, i2);
}
Yes, I can write a custom method, e.g. from_idx
. But having a fallible cast syntax like above, just appears much more elegant, succinct, obvious, and universally memorable to me.
We don’t need new traits to have a trait based conversion operator, but we need new intrinsics if we want to deprecate the as
operator because we have to be able to write implementations of From
and TryFrom
without using as
.
For instance the current implementation for numeric conversion in the std::convert::From trait is :
impl From<$Small> for $Large {
#[inline]
fn from(small: $Small) -> $Large {
small as $Large
}
}
We need an intrinsic to replace the as
in this implementation.
Furthermore, we need to define some trait implementation too, that are not defined yet by neither From
nor TryFrom
like conversion from f64 to u16.
if plat == big { mem::transmute([0, $small]): $Large } else { mem::transmute
etc
as for f64 etc those can be done mathematically and the compiler can optimize them later.
in any case, I don’t like TryFrom, as it does mean we’ll need two separate conversion operators. I also prefer being able to return different types for different conditions.
For example:
Wrapping (256u16) !: u8 == 0u8
256u16 !: Option<u8> == None (or Result<u8, IntFail>)
256u16 !: Result<u8, !> == panic at runtime
Maybe the following syntax sugar would make more sense?
let a = String::"literal"; // String::from("literal")
let b = String::10; // String::from(10)
let c = String::(value); // String::from(value)
And going further:
let x = u16::256;
let y = bool::true;
An intrinsic would be cleaner than an architecture and optimization dependent hack.
It would be even more confusing to me since ::
currently has a completely different purpose.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.