Is there an equivalent to Fortran's select type statement in Chapel?
Asked Answered
R

1

6

I'd like to try out classes and polymorphism in Chapel, so I am trying to get the following example code to work:

module SomeAnimals {

  class Animal {
  }

  class Bird: Animal {
  }

  class Fish: Animal {
  }

  proc Bird.fly() {
    writeln("Flying ...!");
  }

  proc Fish.swim() {
    writeln("Swimming ...!");
  }

} // module SomeAnimals


proc main() {

  use SomeAnimals;

  var anim: Animal;

  anim = new Fish();

  select (anim.type) {
  when Fish do anim.swim();
  }  
  delete anim;

  anim = new Bird();

  select (anim.type) {
  when Bird do anim.fly();
  }
  delete anim;

} // proc main

This compiles, but upon running it, it simply exits without producing any print-out. Apparently, the calls to the anim.swim() and anim.fly() methods, contained within the select statements, aren't executed for some reason. Without making use of these select statements to check the actual type of the polymorphic variable "anim", the code, of course, doesn't compile.

The above example is actually a rather literal translation of a working Fortran 2008 code that makes use of Fortran's "select type" statement. Does Chapel provide a similar statement, or does this example have to be coded in a completely different fashion in order to work in Chapel? I couldn't find anything of relevance in the Chapel documentation.

Ribbentrop answered 2/8, 2018 at 20:30 Comment(0)
E
5

The key for understanding why your code isn't working is that myVar.type in Chapel refers to the variable's static type rather than its dynamic type. So even though you and I can see that anim is a Fish initially and a Bird later, anim.type will always be Animal since it was declared as var anim: Animal; giving it the static type Animal. You can see this by changing your main() function to the following (try it online):

proc main() {
  use SomeAnimals;

  var anim: Animal;

  anim = new Fish();
  writeln(anim.type:string);

  anim = new Bird();
  writeln(anim.type:string);
} // proc main

where the output will be:

Animal
Animal

One way to reason about a class variable's dynamic type in Chapel is to apply the cast operator (:) to it, which behaves similarly to dynamic casts in C++. Namely, if I try to cast a variable whose static type is Animal to Fish but it's really a Bird, I'll get nil back, indicating that the class object was neither a Fish nor a subclass of Fish.

So a rewrite of your main() that behaves as you'd like would be the following (try it online):

proc main() {
  use SomeAnimals;

  var anim: Animal = new Fish();

  var aFish = anim:Fish;
  if aFish then
    aFish.swim();

  delete anim;
  anim = new Bird();

  var aBird = anim:Bird;
  if aBird then
    aBird.fly();

  delete anim;
} // proc main

(where I'm using the shorthand if classVar ... for if classVar != nil ...)

Rewinding to your specific question about whether Chapel has a Fortran-like type select statement, it does not at present. For reasoning about static types (like int vs. real vs. my record R vs. a subclass of C), using the select statement on a variable's type as you did is completely reasonable (or you could provide overloads of a function where we'd choose the correct one based on the argument's static type). But for cases where you're working within a class hierarchy and have to reason about the dynamic type of the object, your main tools will be casting, as above, or dynamic dispatch, or storing an explicit field in the class to distinguish between the cases (which can be thought of as a manual implementation of the dynamic cast).

Enantiomorph answered 2/8, 2018 at 22:40 Comment(8)
PS -- I think it would be completely reasonable to file a feature request proposing some sort of select-style statement that would eliminate much of the repetition that the casting approach above would likely lead to if you had to reason about a large number of cases: github.com/chapel-lang/chapel/issues/newEnantiomorph
Thanks for your answer. I just tried it out and it works nicely. Could you elaborate a bit on how this example should be coded using dynamic dispatch?Ribbentrop
The idea behind using dynamic dispatch would be to define any methods of interest on Animal (where maybe they generate errors) and then to simply call the methods without the casting. This is a purer OOP approach. Here's a TIO example (note that the halt output goes to the "debug" window): tio.run/…Enantiomorph
> it works nicely. < Don't forget to upvote it then! :)Enantiomorph
Ok, I see where you're heading with that. In Fortran-speak, one would need to use an abstract base type with deferred methods. I believe such formal abstract classes would be a more useful addition to Chapel than a select type statement, as I haven't noticed abstract classes being discussed/supported in the Chapel language specification Version 0.985 (I might be wrong though!). Thanks again. I've up-voted your answer but this didn't show up yet, as I just signed up to Stack Overflow and my reputation is still below 15. :(Ribbentrop
Two related features that we've been discussing a lot recently (and which are on-deck as next steps for implementation) are pure virtual functions and/or some form of constrained generic interfaces or "traits". For your specific example, it's not entirely clear to me whether these would help, though, as they'd still seem to imply that all fish must fly and all birds must swim. I'm not sure how abstract classes would help either, though... Seems like you'd still have to have some sort of dynamic cast from a generic animal to "those that can swim" or "those that can fly"?Enantiomorph
I think you are right. I am going to check out the Chapel issues on github then, regarding the "select type".Ribbentrop
In case I was unclear, I'm fairly certain there aren't any issues currently proposing a "dynamic select type" equivalent. So effectively I was encouraging you to feel free to propose such a feature for cases like this if you felt it would help you. The more concrete your proposal (e.g., sketch out what you'd want it to look like and how you'd want it to act?) the better.Enantiomorph

© 2022 - 2024 — McMap. All rights reserved.