R icon indicating copy to clipboard operation
R copied to clipboard

Feat/coerce

Open sebffischer opened this issue 1 year ago • 4 comments

Here, I am trying to address https://github.com/dgkf/R/issues/69

Overview:

  • Add Comparable, InterpretableAsLogical, CoercibleToNumeric traits (I am not too confident yet in whether I like it how it is)
  • Add a type primitive, e.g. type(1L) returns "integer"
  • Add the r_vec! macro, which is relatively convenient

Open questions:

  • do we really want "1" == 1 to return true? I think this should throw an error
  • I am not even sure if we should allow comparing logicals with numerics. Edit: I think we could understand double as a subtype of integer and integer as a subtype of logical. This means I think we should allow for comparisons of logicals with numerics.
  • how to treat null. In R null == null or null == 1 returns logical(0), which is a footgun I think.

Other comments:

  • I think the trait implementation of Comparable, Orderable and CoercibleToNumeric might be expressed more elegantly if we implemented each primitive type as its own struct and then model Obj as a trait as we have discussed elsewhere. This would then allow a coercion implementation analogous to the one for vectors here https://github.com/dgkf/R/blob/7b424191218c3512bf8c3f4b78f893526e75df97/src/object/vector/coercion.rs#L143-L148. But maybe I now simply have a hammer and everything looks like a nail :D

Notes to myself:

  • ~~I have introduced this:~~
     > 2 == true
     [1] false
     > 2 != true
     [1] false
    
  • It would be convenient to have all() and identical() / equal() primitives for the tests

sebffischer avatar Jul 29 '24 05:07 sebffischer

Would you consider using class in place of type? I know that’s a divergence from R, but I’m continually befuddled by Rs mismatched mode/class - especially for numerics - and have been considering consolidating these all under a single function. Whether it’s class or type, I don’t really have a strong preference, but if like to reduce the dimensions of the class inspection.

dgkf avatar Jul 29 '24 13:07 dgkf

Would you consider using class in place of type? I know that’s a divergence from R, but I’m continually befuddled by Rs mismatched mode/class - especially for numerics - and have been considering consolidating these all under a single function. Whether it’s class or type, I don’t really have a strong preference, but if like to reduce the dimensions of the class inspection.

This is a great idea! I think I would tend to type instead of class because I think it would really be great if we could eventually implement some simple type system similar to the one suggested by Jan Vitek.

sebffischer avatar Jul 30 '24 12:07 sebffischer

I was exploring the possibility to implement Obj as a trait, but I don't really think it works, at least not easily (for me). Let's say we haven a trait Obj and then two structs Character and Logical that implement the trait Obj. If we then want to implement PartialEq for dyn Obj, we can try to downcast Obj to its concrete type using std::any::Any, but this means that the PartialEq implementation already needs to be aware of all the types that implement Obj and we need to cover all cases (I think), which means that there is not such a big advantage over the enum approach. Further, there would be the performance hit that you already mentioned.

Edit: I think I might just have used the wrong approach, but I guess it is still not worth it to invest the time to figure this out, as long as there is no clear need for it.

Out of curiosity, I also searched for other language implementations in rust, and the one that I looked at ("rhai") also represented the primitive types as an enum (https://github.com/rhaiscript/rhai/blob/614f8f004be0509902d2a80fc5b85e16cc6aeac7/src/types/dynamic.rs#L61-L103).

Maybe we can also learn something from their approach of encoding mutability into the language-type: https://github.com/rhaiscript/rhai/blob/614f8f004be0509902d2a80fc5b85e16cc6aeac7/src/types/dynamic.rs#L35-L40

However, I think it would be really cool if we could get rid of these kind of lines https://github.com/dgkf/R/blob/08e0c940c62e3d4ca226e74581473733f37efabc/src/object/vector/core.rs#L612-L620 One way would be to add macros, but I wonder if there is a more elegant way to achieve this, but maybe it is just necessary.

sebffischer avatar Jul 31 '24 15:07 sebffischer

In rhai, they also offer a trait that can be implemented to support custom types: https://github.com/rhaiscript/rhai/blob/614f8f004be0509902d2a80fc5b85e16cc6aeac7/src/types/dynamic.rs#L98

And this method here might also be handy to implement for Obj: https://github.com/rhaiscript/rhai/blob/614f8f004be0509902d2a80fc5b85e16cc6aeac7/src/types/dynamic.rs#L261

Another thing that might help for a cleaner solution to the problem that I am trying to solve here, would maybe be to support iterators as a RepType. Currently, casting an Obj::Vector(Vector::Integer) to a Obj::Vector(Vector::Double) is expensive, because it needs to allocate the double. But if we allow for RepType::Iter, we can directly implement the converson mechanism on Obj.

sebffischer avatar Jul 31 '24 18:07 sebffischer