DEV Community

Discussion on: JavaScript Conditional Branching

 
peerreynders profile image
peerreynders • Edited

Sometimes the stars align and you get to "fake it" with a Bitwise OR (|):

const KIND = Object.freeze({
  Equilateral: 'equilateral',
  Isosceles: 'isosceles',
  Scalene: 'scalene',
});

const LEGS = Object.freeze({
  NotEqual: 0x0,
  LargerEqual: 0x1,
  SmallerEqual: 0x2,
});

const keepPositive = (side) => side > 0;
const numericAsc = (a, b) => a - b;

function kind(sides) {
  const triangle = sides.filter(keepPositive);
  if (triangle.length != 3)
    throw new Error(`Not all sides are positive: ${sides}`);

  triangle.sort(numericAsc);
  const [a, b, c] = triangle;
  if (a + b <= c) throw new Error(`Triangle inequality violated: ${sides}`);

  // "faking" pattern matching
  switch (
    (a === b ? LEGS.SmallerEqual : LEGS.NotEqual) |
    (b === c ? LEGS.LargerEqual : LEGS.NotEqual)
  ) {
    case LEGS.SmallerEqual | LEGS.LargerEqual:
      return KIND.Equilateral;
    case LEGS.SmallerEqual:
    case LEGS.LargerEqual:
      return KIND.Isosceles;
    default:
      return KIND.Scalene;
  }
}

console.assert(kind([2, 2, 2]) === 'equilateral', 'Equilateral failed');
console.assert(kind([3, 4, 4]) === 'isosceles', 'Isosceles (first side) failed');
console.assert(kind([4, 3, 4]) === 'isosceles', 'Isosceles (second side) failed');
console.assert(kind([4, 4, 3]) === 'isosceles', 'Isosceles (third side) failed');
console.assert(kind([3, 4, 5]) === 'scalene', 'Scalene failed');
console.assert(kind([0.4, 0.6, 0.3]) === 'scalene', 'Short sides scale failed');
console.assert(throws(() => kind([0, 0, 0])), 'No size failed to throw');
console.assert(throws(() => kind([3, 4, -5])), 'Negative side failed to throw');
console.assert(throws(() => kind([7, 3, 2])), 'Triangle inequality violation failed to throw');
console.log('done.');

function throws(fn) {
  let caught = false;

  try {
    fn();
  } catch (_error) {
    caught = true;
  }
  return caught;
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
robertseidler profile image
RobertSeidler

clever, I had to stare at it for a few minutes to go through all the possibilities.

That's where the real beauty of a neatly syntaxed pattern matching expression could do a great deal to make it super obvious, what one wants to express with their code.

Thread Thread
 
peerreynders profile image
peerreynders

I had to stare at it for a few minutes to go through all the possibilities.

That's possibly because of lack of familiarity.

The Rust equivalent doesn't look that different to me:

fn categorize(mut sides: [T; 3]) -> Option<Category> {
    sides.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
    let [a, b, c] = sides;
    let is_triangle = a + b > c;
    if is_triangle {
        Some(match (a.eq(&b), b.eq(&c)) {
            (true, true) => Equilateral,
            (true, _) | (_, true) => Isoceles,
            _ => Scalene,
        })
    } else {
        None
    }
}
Enter fullscreen mode Exit fullscreen mode

in particular

match (a.eq(&b), b.eq(&c)) {
    (true, true) => Equilateral,
    (true, _) | (_, true) => Isoceles,
     _ => Scalene,
}
Enter fullscreen mode Exit fullscreen mode

In Erlang (and Elixir is similar) something like (again, assuming that the sides are sorted by length so that equal sides will always be adjacent)

case Sides of
  {A, A, A} -> "equilateral";
  {A, A, C} -> "isosceles"; 
  {A, B, B} -> "isosceles";
  _ -> "scalene"   
end.

Enter fullscreen mode Exit fullscreen mode

or

case Sides of
  {A, B, C} when A == B andalso B == C -> "equilateral";
  {A, B, C} when A == B orelse B == C -> "isosceles"; 
  _  -> "scalene"
end.

Enter fullscreen mode Exit fullscreen mode

ReScript (aka ReasonML; JavaScript flavored OCaml)

let kind = switch (a === b, b === c) {
| (true, true) => "equilateral"
| (true, _) | (_ , true) => "isosceles"
| _  => "scalene"
}
Enter fullscreen mode Exit fullscreen mode

etc.

Thread Thread
 
robertseidler profile image
RobertSeidler • Edited

That's possibly because of lack of familiarity.

very likely.

And nice overview, of how different languages handle the same problem