Problem-specifications: Should Triangles tests show that an Equilateral triangle is also Isosceles?

Created on 17 Sep 2016  Â·  11Comments  Â·  Source: exercism/problem-specifications

In the Rust track we got a PR for the Triangle exercise

https://github.com/exercism/xrust/pull/206

Instead of making the change in just Rust, though, I thought it would be better to discuss a track-wide change.

Currently the canonical tests expect the Triangle to be of just one type. Should we change the tests to show that Equilateral is really a sub-type of Isosceles?

Most helpful comment

Git history contains nothing about the purpose of this exercise. I think we get to figure that out for ourselves.

There seem to be two options:

  1. Property Based (in which a triangle can be both Equilateral and Isosceles)
  2. Type Based (in which a triangle can be either Equilateral and Isosceles)

I favor 1, not only because it reflects reality, but because I think it leads to better programs. To discuss why, I'll start with option 2

Type Based

If you do this with a return of an Enum, symbol (as Ruby does), string or object, your program probably has some code that checks on type.

The cpp tests, for example, check on type.

Implementations that use objects check that the return is of the right class. Implementations that use string check that the return is a string (and that it contains the correct value). So, language 'orientation' aside, if the tests require a specific type, the code will involves checks on type.

My belief is that checking on type is not the best approach. It leads to type-checking code in lots of different parts of your application, and that leads to Shotgun Surgery

And, in the case of triangles, what's the approach when you want to identify Obtuse from Acute. These types cut across your existing type structure, suggesting that maybe it's the wrong way to think about triangle types.

Property Based

If we move from checking types to asking about properties, then the tests change to look more like the Rust version. And, bonus, when the specific type-checking code goes away, so do the problems it can bring. A triangle can simultaneously be isosceles, equilateral, acute and oblique. This is both easier to deal with in code (no type-checking match statements all over the place) and a more accurate representation of a triangle.

All 11 comments

The exercise is to classify a given triangle in the most specific way. So even if equiliteral is a sub-type of isoscale, it is more specific and as such the only answer.

On the other hand side, if the exercise were to check if a given triangle is of a given type, you were right.

I do see the point though, that in some (mostly) OO languages, you could in fact specify some type hirarchy that would express exactly what you are telling in your OP, but you can't (easily) do that in many other languages.

Therefore I'd think we shouldn't change the status quo.

PS: I did now look at the rust implementation of the tests. They do not follow the canonical tests exactly. The canonical tests require to return one of the possible types, while you do have a couple of predicates which make you able to check a given triangle for a given type. So for the rust track it would make sense to implement the hirarchy.

What is the purpose of this exercise? What skills is it trying to teach?

The description defines an illegal triangle in terms of _triangle inequality_, but requires the user to know or look up the definitions of _equilateral_, _isosceles_ and _scalene_. Upon implementing a mathematically correct solution, the tests fail.

As it stands, it is teaching to implement an incorrect solution in order to make the tests pass. Alternatives:

  • Describe the problem in detail, making it clear that while an _equilateral triangle_ is a special case of an _isosceles triangle_, the purpose is to classify the triangle as only one of _illegal_, _equilateral_, _isosceles_ or _scalene_... in that order.
  • Change the tests to be mathematically valid.
  • Create a different exercise, where the concepts to be implemented match the problem domain.

@NobbZ, Rust isn't an OO language and the solution is not implemented in terms of a class hierarchy. Could you please provide an example of a language where this is not easy to implement?

@elahn The fact if rust is OO is discussable. I've read arguments for it, but I do not consider it OO as well. That said, lets get back to the actual topic.

As I already said before, the tests require you to return one of 4 values (illegal/error, equilateral, isosceles or scalene) on testing the triangle. In some languages you can totally write some kind of class hirarchy between them. I do not see how this were possible in Haskell and Rust without delving into some depths of the typesystem and move the exercise to a much later point in the track. I do not know how to define such an hirarchy in Erlang, Elixir, C, Go, and many languages more in general.

Your testsuite in Rust on the other hand side as you do test it now is not very strict about following the canonical suite. Since you have a triangle-"object" which you do ask, if it is a certain kind of triangle. Doing it this way makes it very easy to have that hirarchy. One could implement something similar in every language I know.

But I do strongly prefer the enumeration style of the exercise, since it does give us something we can pattern match or case on if our language does give us such constructs.

Ok, so the purpose is to teach enumeration. That rules out changing the tests to be mathematically valid. Do you prefer the option of fixing the exercise description or using a problem domain that naturally fits enumeration?

I do not know if that exercise is meant as I did describe it, that is just
how it feels to me. Also in general I do prefer enumerations over a couple
of predicates, since I can always match on an enumeration, which I do
strongly prefer over chained ifs.

Perhaps someone else, more involved into creating the exercises can explain
the actuall intend?

Elahn Ientile [email protected] schrieb am So., 18. Sep. 2016 um
11:10 Uhr:

Ok, so the purpose is to teach enumeration. That rules out changing the
tests to be mathematically valid. Do you prefer the option of fixing the
exercise description or using a problem domain that naturally fits
enumeration?

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/exercism/x-common/issues/379#issuecomment-247836329,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADmR41OqufTuvfNT6-bsUNuFK2Zxc2Pks5qrQAegaJpZM4J_mrI
.

Git history contains nothing about the purpose of this exercise. I think we get to figure that out for ourselves.

There seem to be two options:

  1. Property Based (in which a triangle can be both Equilateral and Isosceles)
  2. Type Based (in which a triangle can be either Equilateral and Isosceles)

I favor 1, not only because it reflects reality, but because I think it leads to better programs. To discuss why, I'll start with option 2

Type Based

If you do this with a return of an Enum, symbol (as Ruby does), string or object, your program probably has some code that checks on type.

The cpp tests, for example, check on type.

Implementations that use objects check that the return is of the right class. Implementations that use string check that the return is a string (and that it contains the correct value). So, language 'orientation' aside, if the tests require a specific type, the code will involves checks on type.

My belief is that checking on type is not the best approach. It leads to type-checking code in lots of different parts of your application, and that leads to Shotgun Surgery

And, in the case of triangles, what's the approach when you want to identify Obtuse from Acute. These types cut across your existing type structure, suggesting that maybe it's the wrong way to think about triangle types.

Property Based

If we move from checking types to asking about properties, then the tests change to look more like the Rust version. And, bonus, when the specific type-checking code goes away, so do the problems it can bring. A triangle can simultaneously be isosceles, equilateral, acute and oblique. This is both easier to deal with in code (no type-checking match statements all over the place) and a more accurate representation of a triangle.

Git history contains nothing about the purpose of this exercise.

I mostly added early exercises without any particular purpose in mind. Sometimes I'd discover that someone had trouble with a particular topic and I'd try to make something up that would force them to struggle with it a bit. But mostly not. They're all just small puzzles that may or may not teach something useful.

If in retrospect we discover or decide that an exercise has the potential to teach something more specific and interesting, then we should do that. If we discover that it's a terrible/boring/uninteresting exercise, then we should deprecate it.

For context, I think about these exercises as a way of developing a high level of fluency at a low level of proficiency: getting comfortable with syntax and core library functions and idioms and conventions is valuable.

A triangle can simultaneously be isosceles, equilateral, acute and oblique.

I think property based makes better sense.

+1 to property

Ok. Then I think the next steps here are

  • [x] Create an updated triangles canonical-data.json file that implements property based tests
  • [ ] Blazon all existing tracks (yes, Blazon is a verb)
  • [ ] Let the magic happen

I can tackle the updated test file. When that PR is in I'll close this issue.

Was this page helpful?
0 / 5 - 0 ratings