393
votes
\$\begingroup\$

Write a program that seemingly adds the numbers 2 and 2 and outputs 5. This is an underhanded contest.

Your program cannot output any errors. Watch out for memory holes! Input is optional.

Redefining 2+2 as 5 is not very creative! Don't doublethink it, try something else.

\$\endgroup\$

closed as off-topic by Dennis Mar 23 '16 at 4:50

  • This question does not appear to be about programming puzzles or code golf within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

locked by Dennis Mar 23 '16 at 4:50

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. See the help center for guidance on writing a good question.

Read more about locked posts here.

  • 48
    \$\begingroup\$ This is question in book "1984" by George Orwelll. \$\endgroup\$ – bacchusbeale May 30 '14 at 12:23
  • 97
    \$\begingroup\$ Why is this underhanded? Two plus two is five. \$\endgroup\$ – Geobits May 30 '14 at 16:23
  • 79
    \$\begingroup\$ THERE! ARE! FOUR! LIGHTS! \$\endgroup\$ – Nick T May 30 '14 at 19:57
  • 105
    \$\begingroup\$ @Geobits - I agree: 2+2=5 you can see it in this calculator. \$\endgroup\$ – MT0 May 30 '14 at 20:03
  • 47
    \$\begingroup\$ echo "2+2=5"; \$\endgroup\$ – user3459110 May 31 '14 at 12:16

156 Answers 156

17
votes
\$\begingroup\$

Javascript

Here is another fun one. This time in Javascript

function Add(a,b) {
    return a + b;
}

alert(Add(2,2));

if (false) {
    function Add(a,b) { return ++a + b; }
    alert("This code is not to be executed!");
}

The 2nd function is still created and overwrites the first one, even though it is in the false code block. JavaScript creates all functions using the style "function Name" before other code.

\$\endgroup\$
  • 11
    \$\begingroup\$ brb, I need to file a bug report... \$\endgroup\$ – primo Jun 6 '14 at 13:04
14
votes
\$\begingroup\$

Perl

use strict;
use warnings;
sub sum { my $sum = 0; $sum += $_ for @_,0..$#_ ; $sum }
print sum( 2, 2 );

Explanation

Arrays are zero-indexed


And if that isn't underhanded enough:

use strict;
use warnings;

sub sum { my $sum = 0; while (@_ = each @_){ $sum += $_ for @_ } ; $sum }
print sum( 2, 2 );

Explanation

Seemingly innocuous assignment to @_ with each sums up the array indices along with the values.

\$\endgroup\$
  • \$\begingroup\$ The second program produces an infinite loop for me. See here \$\endgroup\$ – Anant Jun 7 '14 at 13:15
  • \$\begingroup\$ @Anant : I know that Perl 5.18 updates the behaviour of each inside while conditionals. The above code works for versions 5.12 to 5.16 \$\endgroup\$ – Zaid Jun 7 '14 at 14:52
  • \$\begingroup\$ Ah okay, thanks! \$\endgroup\$ – Anant Jun 7 '14 at 15:45
11
votes
\$\begingroup\$

C

I ended up writing two solutions. The first was designed to give correct output for all values other than 2+2 and be non-trivial to understand, even though it would be obviously suspicious. The second I'm more proud of, and is harder to see why the wrong answer is output.

First Solution

unsigned int add(unsigned int a,unsigned int b)
{
    return b+(a|(!~((a&1<<1)|(~(a&~(1<<1)))))&(!~(b&1<<1|~(b&~(1<<1)))));
}

This is a simple case of binary operations to check if a == b == 2, and incrementing a - without using any of those operators. Key things to look out for are that 1<<1 is 2, and that logical '!' implicitly casts to boolean, so gives you either 0 or 1 which can be added(using binary OR) to the 2+2 to get 5. Otherwise pretty straight forward, just hard to read.

Second Solution

#include <errno.h>

int main( void )
{
    char* buffer = (char*) malloc( 1024 );

    /// check the buffer allocated correctly before adding into it \\\
    if ( buffer )
    {
        sprintf( buffer,"addition example: 2+2=");  /// add the precursory line of intro text        \\\
        const int result = 2 + 2;                   /// calculate the hardcoded 2+2 sum              \\\
        sprintf( buffer, "%d", result );             
        printf( "%s", buffer );                     /// print out the finished statement to the user \\\
    }else{
        errno = EIO;                                /// EIO - input/output error, see <errno.h>      \\\
        printf("IO Error with error code:\n");
        printf( "%d", errno );
        return -1;
    }

    free( buffer );
    return 0;
}

Far more proud of this one. It pretends to be a simple example on "how to allocate and print to a buffer". Being so nice as to even provide error handling. There are a few different layers that add to it, but the key point is more than 50% of the lines are comments (from '\' escaping the new line in a previous comment). To get the 5, the errno is output with the value EIO, which is defined as 5 in the standard library. To see how it functions, using any good IDE will highlight most lines as comment and show the 4 lines that actually need to execute for it to work.

\$\endgroup\$
11
votes
\$\begingroup\$

piet

Simply pushes two 2's on the stack and adds them. Then outputs result.

It even has a helpfully drawn image of what it is doing.

For the colorblind like me, the tweaks are virtually undetectable.

piet

\$\endgroup\$
10
votes
\$\begingroup\$

Python

Computers really use binary to add.

def in_binary(n):
    if n == 0:
        return [] # base case
    else:
        digit = n & 0x1 # bit mask
        return in_binary(n >> 1) + [digit] # recursion

def from_binary(b):
    # add value of each digit, using enumerate to get its place
    # list comprehensions are Pythonic
    return sum([(2**place) * value
                for place, value in enumerate(b)])

>>> two = in_binary(2)
>>> from_binary(two + two)
5

Try it.

This turns 2 into [0, 1], a reversed-order binary number, then instead of any real binary addition, concatenates the digits to form [0, 1, 0, 1], and then interprets that as a non-reversed-order binary number, which is 5.

\$\endgroup\$
  • \$\begingroup\$ Nice, two tricks hidden. \$\endgroup\$ – Paŭlo Ebermann May 31 '14 at 22:03
  • \$\begingroup\$ An explanation would be nice? \$\endgroup\$ – Jack Aidley Jun 5 '14 at 10:01
9
votes
\$\begingroup\$

C++

#include <iostream>

class Int
{
public:
    Int(const int& a) : integ(a) {}

    friend std::ostream& operator<<(std::ostream& oss, const Int& rhs)
    {
        return oss << rhs.integ;
    }
    int operator+(Int o)
    {
        if(integ == 2 && o.integ == 2)
            return integ+o.integ+1;
        return integ+o.integ;
    }

private:
    int integ;
};

int main()
{
    Int two = 2;
    std::cout << two << " + " << two << " = " << two + two;
}

Output: 2 + 2 = 5

Try online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Same answer I was going to post. Because operator overloading is evil in so many cases! :) \$\endgroup\$ – Mike McMahon Jun 2 '14 at 5:25
  • 2
    \$\begingroup\$ And good in so many other! :D \$\endgroup\$ – NaCl Jun 2 '14 at 15:38
  • 1
    \$\begingroup\$ I wonder if C++14 could make this even better, with user-defined literals. \$\endgroup\$ – JDługosz Mar 18 '16 at 9:47
9
votes
\$\begingroup\$

Commodore 64 Basic

1 POKE 2070, 51
2 PRINT 2+2

The Commodore Basic interpreter's sandboxing is, to put it mildly, non-existent. So why not engage in a bit of self-modifying code? Line 2, as written, is PRINT 2+2, but as executed, it's PRINT 3+2.

\$\endgroup\$
  • \$\begingroup\$ I miss line numbers. \$\endgroup\$ – JDługosz Mar 18 '16 at 9:48
9
votes
\$\begingroup\$

C

#define one 0.6+0.4
#define two one*2
#define zero one*two-two*one

int a = two+two+(zero*zero);
printf("%i",a);

Logs: 5


This one was a lot of fun!

Most humans will automatically put parens around variables. We've been taught to do this in math. x*5 is really (x)*5 because x could be something like 0.4+0.6 but you always simplify variables (in Math). But in compiler, CLANG just inserts it right in, no questions asked. So when I define one as 0.6+0.4 then define two as one*2 a human may see (0.6+0.4)*2 which = 2, but compiler sees 0.6+0.4*2, no parens, which will simplify to 0.6+0.8 which = 1.4

Really compiler reads my int a = as 0.6+0.4*2+0.6+0.4*2+(0.6+0.4*0.6+0.4*2-0.6+0.4*2*0.6+0.4) which is 4.75 --> (int)5.

\$\endgroup\$
7
votes
\$\begingroup\$

Windows Command Script

set /a x = 1
set x = 0
:: this is essentially 0+2+2 right?!
set /a x += 2 + 2
echo %x%

It turns out that "set" with the /a flag ignores spaces before the = sign which normally would be part of the variable name. So "set /a x = 1" would change "x", but "set x = 0" would change "x " (note the space).

\$\endgroup\$
  • \$\begingroup\$ Hmm, using both variants in the same script makes it a bit suspicious. \$\endgroup\$ – Paŭlo Ebermann May 31 '14 at 22:04
  • \$\begingroup\$ At least to those of us who know cmd, that's not very underhanded. That code practically screams the answer ;-) \$\endgroup\$ – Joey Jun 1 '14 at 13:20
7
votes
\$\begingroup\$

Javascript

Use an array.

function add(a, b) {
    var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    return numbers[a + b];
}
alert(add(2, 2))

Will output

5

Javascript arrays will start from zero, but when I defined the array, I started with 1. Therefore, the result will actually be 1 more than it's supposed to be.

\$\endgroup\$
7
votes
\$\begingroup\$

Python

>>> import sys
>>> def dh(obj):
...     if isinstance(obj, int):
...         obj += 1
...     __builtins__._ = obj
...     print(repr(obj))
...
>>> sys.displayhook = dh
>>> 2 + 2
5

Adds 1 to any int-valued expression entered in the REPL.

\$\endgroup\$
7
votes
\$\begingroup\$

Javascript: (8 bytes)

2+2|!![]

Explanation:

(requested in comments)

This is due to implicit type conversion, ![] is false, !false becomes true , then true is implicitly converted to a number type (1) because on the left of the | operator is a number.

Another example:

2+2|!""

"" implicitly converts the empty string to false by ! then is negated by ! operator to true then to a number (1) because on the left of the | operator is a number.

Other variants using other operator and implicit type conversion might be:

2+2|!"" 
2+2|!0

or plain which is shortest (5 bytes)

2+2|1

but putting 1 in there makes is too obvious.

\$\endgroup\$
  • 7
    \$\begingroup\$ How is it "underhanded"? \$\endgroup\$ – nicael Jun 2 '14 at 19:11
  • \$\begingroup\$ @nicael added an explanation \$\endgroup\$ – Eduard Florinescu Jun 3 '14 at 4:35
6
votes
\$\begingroup\$

FORTH

: 2 ; : + 5 ; 2 2 +

I just redefined 2 to do nothing and + to put 5 on the stack.

\$\endgroup\$
6
votes
\$\begingroup\$

Perl 6

I have no idea why it happens. Help.

multi infix:<+>(2, 2) { 5 }
say 2 + 2;
\$\endgroup\$
  • 2
    \$\begingroup\$ It's interesting that the Haskell code that literally does exactly the same thing is the second highest voted answer. Maybe you should have pretended you didn't know how it works. \$\endgroup\$ – primo Jun 6 '14 at 11:37
  • 3
    \$\begingroup\$ +1 because you have no idea how this works. \$\endgroup\$ – Justin Jun 12 '14 at 21:57
  • \$\begingroup\$ Interesting this also changes what 1+1+2 and 3-1+2 returns. \$\endgroup\$ – Brad Gilbert b2gills Dec 29 '14 at 15:13
6
votes
\$\begingroup\$

Mathematica

First, our underhanded part (here directly entered to the kernel; in a notebook, you could delete that line afterwards!)

In[1]:= $Post=#+Boole[!SquareFreeQ@#]&;

Now, let's first verify that everything works as normal:

In[2]:= 2*3

Out[2]= 6

We can even test that 2+2 does really equal 4:

In[3]:= 2+2==4

Out[3]= True

And it certainly does not equal 5:

In[4]:= 2+2==5

Out[4]= False

So now, let's evaluate 2+2:

In[5]:= 2+2

Out[5]= 5

Oops!

$Post is a function that is applied to every expression after normal evaluation. ...& defined an anonymopus function, and # refers to the argument. SquareFreeQ gives true if the expression does not contain a factor that is a square (other than 1), ! is the logical not, as usual, anmd Boole converts the logical value into 0 for False and 1 for True.

Since 6 is square free, the first test is not affected by this: Adding 0 to 6 doesn't change anything.

One might expect an error on the tests giving True or False, but SquareFreeQ just gives True on such values (the same is true for the non-printed Null generated by the first line; otherwise it would have generated Null+1 which would have been printed). Also, the obviously meaningless addition True+0 is no problem for Mathematica; you can add 0 to anything (even a picture, if you desire) and it won't change anything. Therefore also those tests give the expected result.

Finally, we arrive at 2+2. This results in 4, which is not square free, thus $Post[4] evaluates to 5, which is what gets output.

\$\endgroup\$
5
votes
\$\begingroup\$

Ruby

There are all sorts of bizarre meta-programming ways of doing this in Ruby, and I might post one at some point, but for now here’s a goofy bit of obfuscation.

def sum(*args)
  *arg_list,arg_enum=args
  arg_list.first + arg_enum.next
end

p sum(2,2)
\$\endgroup\$
  • 1
    \$\begingroup\$ nice, but this isn't as much underhanded as it is obfuscated. \$\endgroup\$ – John Dvorak May 30 '14 at 18:00
  • 2
    \$\begingroup\$ This looks like it calls Enumerator#next, but it really calls Fixnum#next. To get 4, the code should be def sum(*args); arg_enum = args.lazy.drop(1); args.first + arg_enum.next; end. \$\endgroup\$ – kernigh May 30 '14 at 22:01
5
votes
\$\begingroup\$

Rebmu

I prefer objective golf to the more subjective "underhanded", but if that's the demand, here you go:

stLDtsTC43a&[5]

print do [2 + 2]

That outputs 5. The real payload here could be just 8 chars of poison, +: a&[5], substituting the arity-2 infix function that + is bound to by default with a prefix arity-1 function that always returns 5. Looks like other people have done the same thing and been downvoted, so I've upped the ante a bit with obfuscation.

The transparent version of the poisoning line would be:

+: function [dummy-parameter] [5]

But to try and mask it so no + appears in the poisoning code, it does stLDtsTC43a&[5] ... which translates to set load to-string to-char 43 to do the assignment. So it turns 43 into a character, then into a string, and loads it into structural code (as the single symbolic word +) to use the SET operator on.

After that line runs, basically + anything will will return 5. And since it isn't infix, it's not looking "behind" it to find a first parameter.

If evaluating to 5 were enough, you could just say 2 + 2. But if a print is desired, you can't merely print [2 + 2] and get 5, though. Because PRINT runs a REDUCE step, and keeps all of the values...so the evaluation becomes [2 5] and it prints both numbers. However, by calling the evaluator via DO (which returns the last result, discarding results of all prior evaluations) we throw away the 2...and all PRINT sees is the last value. + 2 is 5.


(Note: For anyone worried that this malleability points to an fatal flaw in Rebol/Red, I'll point out PROTECT:

>> protect '+

>> +: function [dummy-parameter] [5]
** Script error: protected variable - cannot modify: +:

It's a lot like a game of Nomic, for those familiar...)

\$\endgroup\$
5
votes
\$\begingroup\$

Perl

use strict;

sub calculator ($) { @_ }

# Stack-based calculator, so start with an empty array
my @calculation = undef;

# First number to add is 2
push @calculation, 2;

# Operation
push @calculation, "+";

# Next number to add is 2
push @calculation, 2;

# We want to find out what it equals
push @calculation, "=";

# For debugging, let's see what the calculation is
print @calculation;

# Now print the result
print calculator(@calculation);

# And a blank line
print "\n";
\$\endgroup\$
  • \$\begingroup\$ my @calculation = undef;. I was wondering how to initialize an empty array, thanks! \$\endgroup\$ – primo Jun 6 '14 at 11:40
  • \$\begingroup\$ @primo, not sure if you were being serious, but the example above is not a great place to learn Perl from. my @calculation = undef doesn't actually result in an empty array, but rather a single-element array containing undef. It's a necessary step for this slightly obfuscated script to work. \$\endgroup\$ – tobyink Jun 6 '14 at 16:20
  • \$\begingroup\$ That was meant to be a subtle spoiler. Perhaps too subtle... ;) \$\endgroup\$ – primo Jun 6 '14 at 16:32
5
votes
\$\begingroup\$

JavaScript

function add() {
  for (var i = 0; i < arguments.length; i++) {
    rv = (rv || 0) + arguments[i];
  }
  return rv;
}
if (add(0, 0) == 0) console.log("add(0,0) == 0");
if (add(0, 1) == 1) console.log("add(0,1) == 1");
if (add(2, 2) == 5) console.log("... umm ... what?");

Pretty easy to spot if you're looking for it.

\$\endgroup\$
  • \$\begingroup\$ +1 i see what you did there! very tricky! \$\endgroup\$ – markasoftware Jun 6 '14 at 22:54
5
votes
\$\begingroup\$

T-SQL

declare @S varchar(max)
set @S = 0x0D0A6966206E6F74206578697374732873656C656374202A2066726F6D207379732E736368656D6173207768657265206E616D65203D202732202B203227290D0A626567696E0D0A20206465636C6172652040732076617263686172286D6178290D0A2020736574204073203D202763726561746520736368656D61205B32202B20325D270D0A20206578656320284073290D0A2020736574204073203D20276372656174652066756E6374696F6E205B32202B20325D2E5B205D28292072657475726E7320696E7420617320626567696E2072657475726E203520656E64270D0A20206578656320284073290D0A656E64
exec (@S)


select "2 + 2"

/* outputs a 5 */." "()

There is a schema named "2 + 2" with a scalar valued function named " " that always returns a 5. When you call a scalar valued function in SQL Server you have to specify the schema followed by period followed by the function name and parenthesis. The comment /* outputs a 5 */ is inserted after the schema name just to remove the focus from the required ." "() at the end.

create schema [2 + 2]
go

create function [2 + 2].[ ]() returns int as begin return 5 end
go

\$\endgroup\$
  • \$\begingroup\$ I believe creating that schema should be part of the answer. \$\endgroup\$ – aaaaaaaaaaaa Jun 6 '14 at 15:38
  • \$\begingroup\$ @eBusiness I have updated the answer. I did it somewhat obfuscated to keep the challenge for someone who actually knows T-SQL. The select statement is enough to figure out how it is done since it is the only way the syntax valid. \$\endgroup\$ – Mikael Eriksson Jun 7 '14 at 5:17
5
votes
\$\begingroup\$

Haskell (Proof by Curry-Howard Isomorphism)

A mathematical proof that 2 + 2 = 5 in Haskell. The proof is based on the Curry-Howard Isomorphism, where mathematical propositions are expressed as types in a programming language (here 2 + 2 == 5) and mathematical proofs of a proposition P are expressed as terms of type P (here undefined). The proof exploits diverging functions in Haskell to get the paradoxical Qed. data a == b ... defines propositional equality: the type that is inhibited (with Refl) if and only if a and b are judgmentally equal — i.e. a and b simplify to the same expression. The definition is equivalent to the definition of :~:.

{-# LANGUAGE DataKinds, PolyKinds, TypeOperators, GADTs #-}

import GHC.TypeLits

proof :: 2 + 2 == 4
proof = Refl

paradox :: 2 + 2 == 5
paradox = undefined

data a == b where
  Refl :: a == a

infix 4 ==
\$\endgroup\$
5
votes
\$\begingroup\$

DUP

It's simple: 2+2=5.

Try it here.

Hehe, good luck with this one.

Explanation

DUP treats most A-za-z as variables, albeit uninitialized. It pushes 2 uninitialized variables to the stack. 's pushes charcode of s to the stack. Whitespace is entirely ignored. simple pushes 6 more uninitialized variables to the stack, while : takes the top stack item (a variable) and sets it to the second from top stack item. 2 is pushed to the stack, + pops 2 numbers and adds them, 2 is pushed to the stack, = pops 2 numbers and checks for equality, and 5 is pushed to the stack.

Of course, that's all completely irrelevant, because just . outputs the top of the stack (in this case, 5).

\$\endgroup\$
4
votes
\$\begingroup\$

Ruby

class Fixnum
  def +(num)
    5
  end
end

2 + 2
# => 5
\$\endgroup\$
4
votes
\$\begingroup\$

HTML + CSS

<style>
#res {font-family: Audiowide;
width: 10pt;
overflow:hidden;
transform:scale(-1, 1);
-webkit-transform:scale(-1, 1);}
</style>
<link href='http://fonts.googleapis.com/css?family=Audiowide' rel='stylesheet' type='text/css'>

<div id="res">2+2</div>

http://jsfiddle.net/4rNLM/

\$\endgroup\$
4
votes
\$\begingroup\$

C#

class Program
{
    private class Int32
    {
        public static int operator +(Int32 val1, Int32 val2)
        {
            return 5;
        }

        public static implicit operator Int32(int val)
        {
            return new Int32();
        }
    }

    private static void Main(string[] args)
    {
        Int32 num1 = 2;
        Int32 num2 = 2;

        Console.WriteLine(num1 + num2);
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ +1 for a good demo of why I should continue to insist that my team use built-in types rather than System. types. \$\endgroup\$ – ClickRick Jun 1 '14 at 14:24
4
votes
\$\begingroup\$

JavaScript

(NaN).constructor.prototype['\x74\x6f\x53\x74\x72\x69\x6e\x67'] = function(){ return-~this };

alert('2 + 2 = ' + (2 + 2).toString());

Demo Here

Overwrites the Number.toString method with one that returns one more than the current value. Uses unary negation on a bitwise not operation of the value.

\$\endgroup\$
4
votes
\$\begingroup\$

PHP

<?php
// Somewhere in the initialization script
ob_start(function($buffer){return str_replace("4", "5", $buffer);});

// Many lines below
echo 2 + 2;
?>

That simple script will output 5.

ob_start($buffer) handles all the output until the script has finished executing. This is useful, for example, to minimize the html that you want to output, but here it's used only to change all 4 to 5.

\$\endgroup\$
4
votes
\$\begingroup\$

PowerShell

And swing

function sum() {
    $args|%{("$($_[0])"-shr1)+("$($_[2])"-shl1)}
}

sum 2+2  #5

It's not quite "underhanded" in terms of the function, but if you were given a function called "sum", you'd think it would give you the proper value in return. Underhanded enough in my book.

This was an interesting problem to do in Powershell since you can "cast" in all sorts of goofy ways.

$_[0] is a [char], but by wrapping it with "$()" it makes it a string, eliminating three characters if you were to use [string].

I've discovered that using any sort of bitwise operator on a string that can be interpreted as an int, then it casts to int and does the operation.

Powershell also allows for pretty much any character to be part of a variable or function name thus:

function 2+2 {
    5
}

Can be called like . ${Function:2+2} and it will give you 5

\$\endgroup\$
4
votes
\$\begingroup\$

COBOL

I considered how, in a 10,000-line program, most of the DATA DIVISION never gets properly looked at, so I was going to use double-think things like defining ONE as 2 and TWO as 1, or go for misleading 88-level values, or abuse such names as TWO-ONE with a value other than 1 in a COMPUTE, but figured they were too easy. Actually, in a 10,000-line program, they're easy to miss, but this is just a fragment, so they'd not get so easily lost.

That left me really, really not regretting leaving COBOL behind several years ago, and chose instead to prove that 1 + 2 + 1 = 5 in COBOL-land just as easily as in other languages.

   data division.
   working-storage section.
   77  one type Int32 value 1.
   77  two type Int32 value 2.
   77  result type Int32 value 0.

   procedure division.
       move one to result.           *>   RESULT <- 1
       add two to result.            *>   RESULT <- 3
       multiply two by one.          *>   TWO    <- 2
       add one to result.            *>   RESULT <- 4
       display '1 + 2 + 1 = ' result.

Result:

1 + 2 + 1 = +0000000005

.

The MULTIPLY verb puts the result in the second operand, not the first as might be inferred by the casual reader.

\$\endgroup\$
4
votes
\$\begingroup\$

APL

I thought this was nice to share, it happened to me to stumble on this kind of error. Plus, there was no APL answer yet :-).

a←¯1          we set a to be -1
2+a+←3        APL executes righternmost operations first, so 3 is summed to a, obtaining 2
              so proceeding to the next operation (2+) we should get 4 but...
5

This would work if it was split on 2 lines (a+←3 ⋄ 2+a) but doesn't work here because the assignment operation (←) has an implicit result which is the right argument of the assignment (in this case 3). So the 2 is added to the result of the assignment, not to a.

\$\endgroup\$

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