tfakecovariance.nim 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. template accept(x) =
  2. static: assert(compiles(x))
  3. template reject(x) =
  4. static: assert(not compiles(x))
  5. type
  6. BaseObj = object of RootObj
  7. DerivedObj = object of BaseObj
  8. NonDerivedObj = object
  9. Container[T] = object
  10. var base: BaseObj
  11. var derived: DerivedObj
  12. var nonDerived: NonDerivedObj
  13. var baseContainer: Container[BaseObj]
  14. var derivedContainer: Container[DerivedObj]
  15. var nonDerivedContainer: Container[NonDerivedObj]
  16. # We can fake covariance by listing some specific derived types that
  17. # will be allowed with our overload. This is not a real covariance,
  18. # because there will be multiple instantiations of the proc, but for
  19. # many purposes, it will suffice:
  20. proc wantsSpecificContainers(c: Container[BaseObj or DerivedObj]) = discard
  21. accept wantsSpecificContainers(baseContainer)
  22. accept wantsSpecificContainers(derivedContainer)
  23. reject wantsSpecificContainers(nonDerivedContainer)
  24. reject wantsSpecificContainers(derived)
  25. # Now, let's make a more general solution able to catch all derived types:
  26. type
  27. DerivedFrom[T] = concept type D
  28. var derived: ref D
  29. var base: ref T = derived
  30. proc wantsDerived(x: DerivedFrom[BaseObj]) = discard
  31. accept wantsDerived(base)
  32. accept wantsDerived(derived)
  33. reject wantsDerived(nonDerived)
  34. reject wantsDerived(baseContainer)
  35. proc wantsDerivedContainer(c: Container[DerivedFrom[BaseObj]]) = discard
  36. accept wantsDerivedContainer(baseContainer)
  37. accept wantsDerivedContainer(derivedContainer)
  38. reject wantsDerivedContainer(nonDerivedContainer)
  39. # The previous solutions were solving the problem for a single overload.
  40. # Let's solve it for multiple overloads by introducing a converter:
  41. type
  42. OtherContainer[T] = object
  43. proc wantsBaseContainer1(c: OtherContainer[BaseObj]) = discard
  44. proc wantsBaseContainer2(c: OtherContainer[BaseObj]) = discard
  45. converter derivedToBase(c: OtherContainer[DerivedFrom[BaseObj]]): OtherContainer[BaseObj] = discard
  46. block:
  47. var baseContainer: OtherContainer[BaseObj]
  48. var derivedContainer: OtherContainer[DerivedObj]
  49. var nonDerivedContainer: OtherContainer[NonDerivedObj]
  50. accept wantsBaseContainer1(derivedContainer)
  51. reject wantsBaseContainer1(nonDerivedContainer)
  52. accept wantsBaseContainer2(derivedContainer)
  53. reject wantsBaseContainer2(nonDerivedContainer)