re: We don't need a ternary operator VIEW POST

FULL DISCUSSION
 

Great writeup.

I do love the ternary operator. I can see how others get confused though. In an application where everything is written one way (regardless of the way) and another way is introduced, it will add confusion.

Though if your application's style guide enforces the use of the ternary operator, it becomes idiomatic.

const getFee = isMember =>
  isMember ? "$2.00" : "$10.00"

const canDrinkAlcohol = age =>
  age >= 21 ? "True, over 21" : "False, under 21"

const isOld => age =>
  age >= 40 ? "You are never too old!" : "Nope"

// YUCK. inconsistent.
function canDrive(age) {
  if (age >= 16) {
    return "Yes"
  } 
  return "Nope"
}

The key to being idiomatic is is consistency. This can be made true even with a nested ternary!

 

Here is another read up about ternaries explaining why/how they can be great even when being nested: medium.com/javascript-scene/nested...

 

To me, that style with the ternary is a little frustrating because it feels like it's so close to someone embracing a more functional style. It's not that ternary can't exist or be useful in that case, but it just seems like a tease at that point. Like, to take your example and convert it into an admittedly contrived example, it might look something like:


const greaterThanOrEq = left => right => left >= right;
const explainDecision = decision => successMessage => failureMessage =>
    (decision && successMessage) || failureMessage;
const canDrinkAlcohol = age => greaterThanOrEq(age)(21);
const isOld = age => greaterThanOrEq(age)(40);
const canIDrink = age => explainDecision(canDrinkAlcohol(age))("yes")("no");
const amIOld = age => explainDecision(isOld(age))("You are never too old!")("Nope");
console.log(canIDrink(22));
console.log(canIDrink(19));
console.log(amIOld(45));
console.log(amIOld(39));
 

LOL I feel the exact same way. The Ternary feels like an in-between. Somewhere in the middle of imperative and functional.

Today I was actually working on a style guide for a project I'm working on. It looks exactly like the code you created.

const getOrdersText = ifElse (hasOrders) (orderCountText) (noOrderCountText)

It's not quite ready for human consumption, but I think you would find it interesting. Hit me up on Twitter if interested in a sneak peek.

Cheers!

The problem with this is that both orderCountText and noOrderCountText will be evaluated in either case.
Do they have to be functions?

The problem with this is that both orderCountText and noOrderCountText will be evaluated in either case.

only one function will execute in this case, either the if case or the else case, but never both.

In my version of ifElse, they can be values that will be returned or functions to be executed.

Yeah, whereas in condition ? expensiveGet() + 1 : expensiveGet2() - 1 only one expression will be evaluated.

const expensiveGetPlus = x => y => expensiveGet(y) + x

ifElse (condition) (expensiveGetPlus (1)) (expensiveGetPlus (-1)) (true)

Check out Sanctuary's ifElse sanctuary.js.org. You can live edit their page to see how it works.

I'd love to get some live editing docs page for my stuff too. Pretty neat site.

I see it's actually for threading through the value, just like tap:

S.ifElse(x=>typeof x === "number")(x=>x-1)(x=>x+"a")(3)
 2

S.ifElse(x=>typeof x === "number")(x=>x-1)(x=>x+"a")("banana")
 "bananaa"

However, for normal conditional use it's error prone, as you've shown in your code. Both expensive gets will run before the condition is even applied to true.
The actual code would be

const expensiveGetPlus = x => () => expensiveGet() + x
const expensiveGet2Plus = x => () => expensiveGet2() + x

ifElse (condition) (expensiveGetPlus (1)) (expensiveGet2Plus (-1)) (true)

That's correct, ifElse accepts functions. So those functions are only executed when the condition is met.

Both expensive gets will run before the condition is even applied to true.

This is still false. Only one will run. Never both.

const isEven = n => n % === 0
const logEven = n => console.log(`${n} is Even!`)
const logOdd = n => console.log(`${n} is Odd`)

ifElse (isEven) (logEven) (logOdd) (10)

//=> "10 is Even!"

You can see logOdd is never called.

In your first example

const expensiveGetPlus = x => expensiveGet() + x

ifElse (condition) (expensiveGetPlus (1)) (expensiveGetPlus (-1)) (true)

both run.

const expensiveGet = () => {
  console.log("doing expensive get")
  return 2
}

Yes you are correct. The expensiveGet method needs to take 2 arguments for it to work the way it is being called in ifElse.

I have created a working example that you can run.

const S = require('sanctuary')

const expensiveGet = (y) => {
  console.log("doing expensive get for", y)
  return 2
}
const condition = x => x === 100
const expensiveGetPlus = x => y =>
  expensiveGet(y) + x

S.ifElse (condition) (expensiveGetPlus (1))
  (expensiveGetPlus (-1)) (100)
//=> "doing expensive get for 100"

This example will show that ifElse only executes one of the functions.

code of conduct - report abuse