FOIL Python's strong typing!

35

1

Your task is to write some code in Python 2 or 3 such that this expression:

(a+b)(c+d) == a*c + b*c + a*d + b*d

will evaluate to True without raising any exceptions.

To clarify, I will copy your code into a file, then from the file import *. Then I will type the expression into the console and verify that it is True.

This is code-golf, so the answer with the shortest length (in bytes) wins.

Esolanging Fruit

Posted 2016-10-28T22:53:24.467

Reputation: 13 542

Answers

20

54 52 50 49 48 45 39 bytes

Removed 4 bytes thanks to Dennis.

The latest version is inspired by the "some reason" in xnor's answer.

class t(int):__add__=type
a=b=t()
c=d=0

jimmy23013

Posted 2016-10-28T22:53:24.467

Reputation: 34 042

Nice! There's 0 .__mul__ for lambda y:0 but it's the same length. – xnor – 2016-10-28T23:28:53.010

x.count saves a byte. – Dennis – 2016-10-28T23:36:31.490

With a=t();b=c=d=0, you can use class t(int):__add__=lambda*x:t to save three bytes. – Dennis – 2016-10-29T00:24:40.770

@Dennis Thanks. Good idea... – jimmy23013 – 2016-10-29T00:32:37.737

1I don't get it... type(t(), t()) or t().type(t()) throws an exception, so what is happening when you do t() + t()? – feersum – 2016-10-29T03:56:20.757

@feersum just type(t()). The LHS becomes (type(b))(0) or t(0), which is equal to 0. – Jonathan Allan – 2016-10-29T09:59:46.080

@JonathanAllan But + is a binary operator. Why would __add__ be called with 1 argument? – feersum – 2016-10-29T10:10:09.497

1@feersum __add__ is called with two, but the first is interpreted as self, only other is passed to type. Weird, yes. – Jonathan Allan – 2016-10-29T10:12:28.543

@feersum The difference is, I believe, that inbuilts use method-wrappers (py3) or unbound methods (py2) (rather than methods or bound methods respectively, like MySpam.__myEggs__ would usually be). I could well be wrong though, interested to know... – Jonathan Allan – 2016-10-29T10:23:39.453

@JonathanAllan But try this: numargs = lambda *a: len(a); class t(int): __add__ = numargs t() + t() results in 2! – feersum – 2016-10-29T11:03:56.470

1

@feersum: a + b first tries a.__add__(b). a.__add__ is type, so that becomes type(b). The key difference between this case and the usual case for methods is that usually, a.__add__ would be a different object from the thing you set __add__ to in the class definition, due to the descriptor protocol, which ordinary function objects implement. (There are also a few other tricky bits that aren't relevant here.)

– user2357112 supports Monica – 2016-10-29T18:25:17.497

10

54 bytes

class m(int):__call__=__add__=lambda*x:m()
a=b=c=d=m()

Make an object that inherits from int, except adding or calling just returns a copy of itself.

Same length:

class m(int):__call__=__add__=lambda a,b:a
a=b=c=d=m()

I thought min or {}.get would work in place of lambda a,b:a, but for some reason they act only on the second argument.

xnor

Posted 2016-10-28T22:53:24.467

Reputation: 115 687

1(it's [tag:code-golf]) – Addison Crump – 2016-10-28T23:10:24.187

1Oops, I only saw [tag:programming-puzzle], will golf. – xnor – 2016-10-28T23:11:06.130

3That was quite a reduction o-o – Addison Crump – 2016-10-28T23:19:06.077

@xnor It doesn't work because min already has a __self__ attribute, so the class skips binding its own self. Why min has __self__ is another question... – matsjoyce – 2016-10-29T19:00:42.260

@matsjoyce: No, it doesn't have anything to do with the fact that min has a __self__. min.__self__ is just an artifact of how built-in functions and built-in methods are implemented as the same type. min doesn't work here because unlike functions written in Python, built-in functions don't support the descriptor protocol, which is responsible for binding the first argument. – user2357112 supports Monica – 2016-10-30T01:07:16.123

@user2357112 Ah, OK, I thought I got it working with sum yesterday, guess I was looking at wrong thing then. – matsjoyce – 2016-10-30T14:43:43.343

3

81 66 bytes

class e:__mul__=lambda*o:0;__add__=lambda*o:lambda x:0
a=b=c=d=e()

Jonathan Allan

Posted 2016-10-28T22:53:24.467

Reputation: 67 804

1

68 bytes

While it cannot really compete with the existing answers, this one actually performs the calculation in question:

from sympy.abc import*
type(a+b).__call__=lambda x,y:(x*y).expand()

Explanation:

  • SymPy is a module for symbolic computations.
  • sympy.abc contains all single-letter symbols, in particular ones named a, b, c, and d.
  • a+b is an Add object, which represents a general sum.
  • type(a+b).__call__= […] monkey-patches the Add class to give it evaluation capabilities, in this case enabling it to work like a multiplication of caller and callee.
  • expand is necessary to make the expressions actually equal (since SymPy only performs thorough equality checks on demand).

Wrzlprmft

Posted 2016-10-28T22:53:24.467

Reputation: 2 772