Function comparing 2 variables of any type

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.

1 Like

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.

3 Likes

my computer is not at hand,but I think assert_eq! may fit.

1 Like

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.

3 Likes

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
    }
}
13 Likes

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.

1 Like

That's what I have been looking for. Thank you Hyeonu :slight_smile:

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.

5 Likes

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.