2

I've never seen a programming language with conditional assignment targets, eg.:

// If (x == y), then var1 will be set to 1, else var2 will be set to 1
((x == y) ? var1 : var2) = 1

The target of the assignment is determined conditionally at run-time, in this case based on whether x == y.

It seems like it could be a handy syntax.

Anyone know of any programming language which supports this?

Or is there a theoretical reason it can't be done effectively?

6
  • 1
    Yes, see here: stackoverflow.com/questions/1082655/… Dec 11, 2015 at 11:21
  • Does it break the compositionality of the language. since the left side of the assignment has to represent a variable reference in this context, while it normally returns a value in other contexts? Ie. the expression changes meaning not based on what it's composed of but what is surrounding it... Dec 11, 2015 at 11:21
  • Ahhhh good point Kilian. It seems like a bit of a hack in C++ though using simulated reference. Can anyone think of a language which actually implements it natively? Dec 11, 2015 at 11:23
  • 2
    It's not a reference, it's an lvalue. This is a fundamental concept in C++ around which the language is built, so no, this is not a weird exception and it doesn't "break" anything. Dec 11, 2015 at 11:23
  • 1
    @BrendanHill: It's no more a "hack" than *ptr = val Dec 11, 2015 at 11:37

2 Answers 2

6

This isn't really a theory question, but a practical one.

C++ supports what you're asking about:

[C++14: 5.16/4]: If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category [..]

For example:

#include <iostream>

int x = 3, y = 4;

void foo(const bool b)
{
    (b ? x : y) = 6;
}

int main()
{
    std::cout << x << ' ' << y << '\n';   // 3 4
    foo(true);
    std::cout << x << ' ' << y << '\n';   // 6 4
    foo(false);
    std::cout << x << ' ' << y << '\n';   // 6 6
}

(live demo)

(This is basically the same as *ptr = val, since dereferencing produces an lvalue.)

It's worth noting that C doesn't support it:

#include <stdio.h>
#include <stdbool.h>

int x = 3, y = 4;

void foo(const bool b)
{
    (b ? x : y) = 6;
}

int main()
{
    printf("%d %d\n", x, y);   // 3 4
    foo(true);
    printf("%d %d\n", x, y);   // 6 4
    foo(false);
    printf("%d %d\n", x, y);   // 6 6
}

// main.c: In function 'foo':
// main.c:8:17: error: lvalue required as left operand of assignment
//      (b ? x : y) = 6;
             ^

(live demo)

… though it will allow you to simulate this technique, by applying my early observation regarding pointer dereferences:

*(b ? &x : &y) = 6;
4
  • 2
    Ha, I had no idea, awesome! Dec 11, 2015 at 11:42
  • 5
    Awesome? More like aweful :-)
    – Stephen C
    Dec 11, 2015 at 12:42
  • 1
    But you can simulate it in C, if you want: *(b ? &x : &y) = 6; Dec 11, 2015 at 14:19
  • 3
    @Deduplicator: lol yuk Dec 11, 2015 at 14:38
3

You can do this in Perl. It is the same as in C++.

my $x = 0;
my $y = 0;

1==1 ? $x: $y = 1;

print "x: $x y: $y\n";

$x = 0;
$y = 0;

1==0 ? $x: $y = 1;

print "x: $x y: $y\n";

Note: this construct can often lead to confusion. For example, consider the following code:

$condition ? $y = 0 : $x = 1;

The person writing this line of code likely thought that $y would get set to 0 if $condition is true, but actually this evaluates to $y = 0 = 1, which gives $y a value of 1.

1
  • Thanks! I agree that it's a confusing syntax. Handy though if used appropriately Dec 11, 2015 at 12:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.