A tricky problem. I have to implement a function fn eq( a, b )
comparing a and b. The function should return false
if either types of variables are different or variables have different values. The function should return true
if both type and value are the same.
If the types don't have any embedded references, you can use std::any::TypeId
to do this:
fn eq<A:'static, B:'static>(_:A, _:B)->bool {
std::any::TypeId::of::<A>() == std::any::TypeId::of::<B>()
}
For non-'static
types, I think you'll need some kind of specialization, which is still an unstable feature.
my computer is not at hand,but I think assert_eq! may fit.
Hi! Thank, you. It's good as starting point for me. But solution should not only compare types, but values of variables in the case type is the same.
Obviously that does not work:
fn eq<A: PartialEq + 'static, B: PartialEq + 'static>(a: A, b: B) -> bool {
if std::any::TypeId::of::<A>() != std::any::TypeId::of::<B>() {
return false;
} else {
return a == b;
}
}
Is it possible to solve the problem without a macros?
^-- That is the original problem statement, which @2e71828 's solution solves.
Not sure I understand how transmute can help. Probably I phrased the problem poorly.
Why not just returning false in the case of different types? Or your idea that the transmute
will do nothing for the same class, but will calm down the compiler? Is such solution okay?
Did you mean that?
fn eq<A: PartialEq + 'static, B: PartialEq + 'static>(a: A, b: B) -> bool {
if std::any::TypeId::of::<A>() != std::any::TypeId::of::<B>() {
return false;
} else {
unsafe {
return std::mem::transmute::<A, B>(a) == b;
}
}
}
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> src/main.rs:163:14
|
163 | return std::mem::transmute::< A, B >( a ) == b;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: source type: `A` (this type does not have a fixed size)
= note: target type: `B` (this type does not have a fixed size)
You don't need any unsafe here.
use std::any::Any;
use std::cmp::PartialEq;
fn cmp(a: impl PartialEq + 'static, b: impl PartialEq + 'static) -> bool {
if let Some(b_cast) = (&b as &dyn Any).downcast_ref() {
&a == b_cast
} else {
false
}
}
Ignore my attempted solution. I have no idea how to force a size_of(A) == size_of(B) requirement that std::mem::transmute requires.
Go with @Hyeonu 's solution.
That's what I have been looking for. Thank you Hyeonu
Hyeonu what do you recommend to read? Is it possible to implement it without dynamic typing, so that implementation was at compile-time?
Thank you for hints.
There's no dynamic dispatch in example above, as you can check on playground. If you select "Show Assembly", you'll see that cmp
is compiled to the following:
playground::cmp:
cmpl %edi, %esi
sete %al
retq
playground::cmp:
xorl %eax, %eax
retq
(not sure how they are really selected, however - looks like the ASM output is missing something).
You can see that there are two versions: one checks the equality of arguments, another immediately returns false
(xor X, X
is a simple way to set X
to 0); everything using dyn Any
is entirely optimized out.
Amazing! Thank you!
It seems such implementation has very limited application because of static restriction. Is it possible to remove static restriction?
I am getting:
error[E0759]: `other` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:128:29
|
117 | fn eq( &self, other : &Logic< RightRef, RighCopy > ) -> bool
| ---------------------------- this data with an anonymous lifetime `'_`...
...
128 | Logic::ValNode( e2 ) => return identical_tolerant( &e1, &e2 ),
| ^^ ------------------ ...and is required to live as long as `'static` here
| |
| ...is captured here...
Without further context, no you can't.
Ah.. Does not it make using Any impractical? Must be another solution exist.