Why does Space Age in Rust use traits?

I think the base code for Space Age in Rust is too complicated and probably not idiomatic. It looks like code ported from an OO language and fails to use Rust’s features well.

It makes no sense to me to define the planets as structs (as they hold no data), just to implement a Planet trait for each. Rust has functional features and the same problem could be solved much more simply in the same way it is done in OCaml (and SML, Haskell, etc): define an enum Planet with the planets as values, then define a single function that does pattern matching and returns the duration for each planet.

I tried to delete the base code and do the simpler solution instead, but the tests require that the planets are structs which implement a years_during method.

(I don’t know if this should be an issue in the rust repo, but I can create one there if it’s preferred)

1 Like

This is usually referred to as the strategy pattern and it is very idiomatic.

The instructions have great hints about how to solve this exercise elegantly and concisely: default implementations in trait methods and declarative macros.

In some situations, both enums and traits can be used to solve a problem. But they are two diferent ways to express the solution, a different perspective so to speak. In this case, the trait Planet might express that a planet is something that revolves around the sun, since something that doesn’t couldn’t implement the required method. An enum would express that there is a finite, well-known list of planets. Both are equally valid.

Maybe you wish to rename the trait to SolarSatellite? The test suite allows that. Then you can implement it for Pluto as well, maybe comets. And the downstream users of your library can even implement it themselves for their favorite asteroid. I hope you get the point.

There are other exercises designed around enums. This one showcases the strategy pattern.

In this case, the trait Planet might express that a planet is something that revolves around the sun , since something that doesn’t couldn’t implement the required method. An enum would express that there is a finite, well-known list of planets. Both are equally valid.

There is, in fact, a finite, well-known list of planets :grinning: We’re not discussing the expression problem.

Of course doing it with structs and traits is valid, I just think it’s very over-engineered for such a simple problem. And adding macros is bringing yet more machinery to a straightforward problem.

I understand that it is an exercise and it could be used to practice these features, but this particular exercise is easy in other tracks and it being so complex for Rust may just reinforce the idea that Rust is a complicated language. There are many exercises in the Rust track and I expect that traits and macros are explored in some of them.

An idea: to write the tests in a way that could support both solutions. The text could discuss the trade-offs and possibilities.

1 Like

Having a narrowly-defined API for the exercises is one of Exercism’s strengths. It allows the language tracks to guide users to learning specific things. If you want to solve exericses in a more free-form manner, then I would recommend advent of code.

There is no requirement for language tracks to implement exercises in the same way as other tracks. To compare how different languages can solve the same problem, rosetta code is a great resource.

The purpose of our exercises is not to hide language features and common patterns from users as a marketing strategy to make Rust look like a simple language. On the contrary, our users have already decided they want to learn the language and are coming to us to be exposed to as much as there is to learn about it.

I have no objection to your last suggestion, other than that I see no way to do this without breaking existing solutions (and thereby wiping the community solutions tab). I would avoid that without good reason.

The strategy pattern is used to have different objects provide different behaviours dynamically. As the logic is the same with every planet and only data is different, I don’t see how this exercise would be relevant for the strategy pattern.

1 Like

I won’t get into splitting hairs about what does or doesn’t classify as the strategy pattern. This is how the pattern is implemented in Rust. A trait plus one type for each strategy. The exercise intentionally pushes students to do that specific implementation and there is value in that.

I believe students will typically realize on their own that this pattern can be used both for data and behavior.

This is a very surprising way to approach all this, this exercise as well as the Strategy pattern (which is never about data, BTW, this is a very weird take on that pattern). I do not share your optimism on the pedagogical aspect.

I think this is to teach how structs work, not to represent the best solution to the problem