LWN.net Logo

PHP: a fractal of bad design (fuzzy notepad)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 8:54 UTC (Tue) by tialaramex (subscriber, #21167)
In reply to: PHP: a fractal of bad design (fuzzy notepad) by slashdot
Parent article: PHP: a fractal of bad design (fuzzy notepad)

I love the result that the operator == is not transitive. That's genuinely brilliant, like COME FROM or a rule requiring you to write integer constants in Roman Numerals.


(Log in to post comments)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 16:06 UTC (Tue) by dtlin (✭ supporter ✭, #36537) [Link]

To be fair, == isn't transitive in Javascript either.
0  == '';   // true
0  == '0';  // true
'' == '0';  // false

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 16:18 UTC (Tue) by k8to (subscriber, #15413) [Link]

Javascript is a mix of acceptable, interesting, and terrible. The terrible is bounded and javascript professionals must learn to avoid it as part of their work. Tools are built which help to find and avoid these problems, and books are written that guide us in using it acceptably.

PHP is.. well.. the article says it better than I can. There's no book titled "PHP, The Good Parts."

I guess what I'm saying is the "to be fair" thing just damns them both, but Javascript is salvageable, and we sort of must if we wish to program web pages, though we can hope for salvation from Dart.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 16:33 UTC (Tue) by HelloWorld (guest, #56129) [Link]

> though we can hope for salvation from Dart.
Yeah right, a language with explicit typing, the null problem and an unsound type system. Dart is broken, and unlike JavaScript, it's not even widely supported.

If you actually want a sensible language for web development, try js_of_ocaml.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 17:35 UTC (Tue) by k8to (subscriber, #15413) [Link]

Sorry if it wasn't obvious; it was meant as dark humor.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 18:11 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link]

I'm actually looking at Kotlin right now. It supports compilation into JavaScript and it's fairly OK as languages go.

BTW, it has explicit nullable types.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 19:13 UTC (Tue) by nix (subscriber, #2304) [Link]

Why did I not know about js_of_ocaml before now? Talk about concentrated awesome. (There must be some catch.)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 16:30 UTC (Tue) by khim (subscriber, #9252) [Link]

This is old news. And yes, JavaScript is almost as terrible as PHP. In some sense it's worse then PHP because with PHP you can just say no while JavaScript is often unavoidable. Even if you use something like ASP.NET or GWT you still sometimes need to delve unto generated JavaScript.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 18, 2012 15:59 UTC (Wed) by HelloWorld (guest, #56129) [Link]

JavaScript isn't unavoidable, there are compilers for sane languages that generate JavaScript output. One such compiler is js_of_ocaml.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 17:03 UTC (Tue) by butlerm (subscriber, #13312) [Link]

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 17:32 UTC (Tue) by nybble41 (subscriber, #55106) [Link]

No, I'm pretty sure they meant "transitive". Commutative is (A == B) <=> (B == A). Transitive is (A == B) && (B == C) <=> (A == C).

> To be fair, == isn't transitive in Javascript either.
>
> 0 == ''; // true
> 0 == '0'; // true
> '' == '0'; // false

The first line is backwards, strictly speaking, but ('' == 0) is also true. Substituting that form, we have A = '', B = 0, and C = '0'. (A == B) and (B == C) are thus both true, but (A == C) is false, so the relation is not transitive.

Equality may not be commutative in all cases, either, but for that you would need different examples. All of the cases listed here are commutative.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 18, 2012 15:08 UTC (Wed) by k3ninho (subscriber, #50375) [Link]

Commutivity is more-often defined in terms of the sequence you use operators. It's not obvious, but Equality is the operator in your example. An alternative example: Commutative means that, for functions A:x->x, B:x->x: A(B(x)) == B(A(x)).

K3n.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 18, 2012 19:43 UTC (Wed) by dtlin (✭ supporter ✭, #36537) [Link]

Indeed. The word for a == bb == a is reflexive.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 18, 2012 20:18 UTC (Wed) by nybble41 (subscriber, #55106) [Link]

> Indeed. The word for a == b iff b == a is reflexive.

The answer is "both". The equality _relation_ is reflexive. The equality _operation_ is commutative.

> Commutative means that, for functions A:x->x, B:x->x: A(B(x)) == B(A(x)).

This doesn't fit any definition of "commutative" I was able to find. Every case I could locate involved the order of _operands_ to a single _binary_ function. Of course, you can turn you example into something like that, though with slightly different types, using higher-order functions (in pseudo-Haskell):

f1, f2 :: (a -> b) -> b
f1 = \f -> f A
f2 = \f -> f B
f1 (f2 (==)) == f2 (f1 (==))

but that is equivalent to the much simpler form:

(==) B A == (==) A B

or:

(B == A) == (A == B)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 19, 2012 22:55 UTC (Thu) by mmorrow (subscriber, #83845) [Link]

>> Commutative means that, for functions A:x->x, B:x->x: A(B(x)) == B(A(x)).

> This doesn't fit any definition of "commutative" I was able to find.
> Every case I could locate involved the order of _operands_ to a single _binary_ function.

The elusive binary operator here is function composition ;)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 19, 2012 23:14 UTC (Thu) by mmorrow (subscriber, #83845) [Link]

> The elusive binary operator here is function composition ;)

A reference for the interested being:
http://en.wikipedia.org/wiki/Centralizer_and_normalizer

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 20, 2012 0:03 UTC (Fri) by nybble41 (subscriber, #55106) [Link]

>>> Commutative means that, for functions A:x->x, B:x->x: A(B(x)) == B(A(x)).
> The elusive binary operator here is function composition ;)

I thought you were presenting a general version of the commutative property, not a specialized version for function composition. That explains why I couldn't reconcile your example with other commutative operators (equality, addition, multiplication) without making "x" the operator and "A" and "B", in essence, the parameters.

Writing "(A . B)(x) == (B . A)(x)" or "A . B == B . A" would make the commutative part of the formula a bit more visible--not that it was really hidden. I just wasn't looking at it from the right perspective.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 20, 2012 0:29 UTC (Fri) by mmorrow (subscriber, #83845) [Link]

> I thought you were..

(I wasn't the author of the original comment.)

> Writing "(A . B)(x) == (B . A)(x)" or "A . B == B . A" would make the commutative part of the formula a bit more visible..

It definitely would have made it clearer.

> ..a general version of the commutative property, not a specialized version for function composition..

Ah, but actually the case where a binary operator is commutative over its entire domain is the special case (in the mathematical sense, blah).

It's just that in programming we don't often (explcitly) deal with non-commutative binary operators, and even less often with non-commutative operators which are commutative when restricted to a subset of their domain.

Here's a quick roughly-phrased example:

Consider a rubik's cube. Think of a "move" as a function which maps a cube configuration to another configuration. This is a non-commutative group with elements these cube-config-maps and binary operator function composition. Now, for any two moves f and g which don't "interfere" (e.g. rotate top, rotate bottom), (f . g) == (g . f).

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 20, 2012 1:13 UTC (Fri) by mmorrow (subscriber, #83845) [Link]

Here's a better example:

The "elements" are C stmts thought of as mappings of memory configurations, and the binary operator is `;`. This is a monoid with identity element the empty C stmt.

Define,

modify(S) := the set of memory locations statement S *may* modify.

So now, `;` is commutative for every pair of statements S,T which *must not* (i.e. cannot under any possible dynamic execution path) modify one or more of the same memory locations.

(S ; T)===(T ; S) <==> modify(S)/\modify(T)==empty_set

(where "===" := equivalence wrt effect on memory)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 20, 2012 1:37 UTC (Fri) by mmorrow (subscriber, #83845) [Link]

Actually that's not quite correct, it's more like:

(S ; T)===(T ; S)
<==>
modify(S)/\modify(T)==empty_set
AND
read(S)/\modify(T)==empty_set
AND
read(T)/\modify(S)==empty_set

or something along these lines, but the idea is clear.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 20, 2012 8:19 UTC (Fri) by mpr22 (subscriber, #60784) [Link]

Programmers tell their programs to subtract, divide, and/or shift fairly frequently.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 19, 2012 15:01 UTC (Thu) by yaap (subscriber, #71398) [Link]

What you wrote is commutativity not reflexivity. Reflexivity for equality is the fact that "a == a" is true for all a.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 17, 2012 17:37 UTC (Tue) by k8to (subscriber, #15413) [Link]

More on this javascript behavior can be found in this highly intellectual talk.

https://www.destroyallsoftware.com/talks/wat

(Okay I'm lying, but it's funny!)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 21, 2012 16:10 UTC (Sat) by IkeTo (subscriber, #2122) [Link]

But === is not transitive even for Java! (Exercise: Try figuring out the type T1, T2 and T3, and values v1, v2 and v3, causing:

T1 a = v1;
T2 b = v2;
T3 c = v3;
System.out.println(a == b && b == c && a != c); // print "true"
)

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 22, 2012 10:02 UTC (Sun) by ajf (subscriber, #10844) [Link]

I don't have a compiler at hand here, but auto-boxing introduced in Java 5 is usually the culprit behind "surprising" Java behaviour. I sometimes have Eclipse configured to mark up implicit conversion between primitive and boxed object (but to be honest it's usually not worth it; I've never encountered any such surprises anywhere other than intentional puzzles like yours).

One possible answer, then, would be that T1 and T3 are Integer, while T2 is int; v1 and v3 are both new Integer(1000), and v2 is 1000. The a == b and b == c expressions will un-box a and c respectively, but a == c will compare object references (and find them different since both were constructed with new).

Another fun quirk only ever encountered in puzzles like this: if you change v1 and v3 to, say, 7, (ie, a primitive value that will be boxed in order to be assigned to a and c), you'll get "false" instead, because a != c will be false, since Integer.valueOf(int) (which is the method called to convert the primitive values to Integer objects to be assigned to a and c) happens to maintain a pool of Integer objects for small values, and will return the same value for both a and c.

Getting back to the topic at hand, the difference to note here is that these are carefully-crafted puzzles in Java; the problem with PHP is that quirks like this are something you more or less always have to think about when you're writing PHP.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 22, 2012 12:25 UTC (Sun) by IkeTo (subscriber, #2122) [Link]

You're right. The following program exhibit the said behavior:

public class T {
    public static void main(String[] args) {
        Integer a = 1000;
        int b = 1000;
        Integer c = 1000;
        System.out.println(a == b && b == c && a != c);
    }
}

Amazingly, there is another ways to cause the said behavior using only primitive types. (See IPSC 2008 Problem C).

And yes, I just try to be humorous when I said "even Java equality is not transitive". PHP is so horribly broken that I won't even touch it with a ten feet pole.

On the other hand, if even the very well specified Java language has non-transitive equality, you can expect that most other languages have similar behavior. One thus cannot just say a language is bad because of it. Instead, one would instead say something like "PHP equality has very surprising behavior that makes it very undesirable for programmers".

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 22, 2012 18:24 UTC (Sun) by Cyberax (✭ supporter ✭, #52523) [Link]

Well, use of equality for object types in Java is dangerous. Which is told in every textbook on it.

On the other hand, the real equality comparison operation ('equals' method) is transitive and commutative. Well, unless you screw it up intentionally.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 26, 2012 0:10 UTC (Thu) by IkeTo (subscriber, #2122) [Link]

It depends on what you call "screw it up intentionally". The following program output "true" for most numbers larger than 16777216 or smaller than -16777217. It is 127/128 of the range [-2^31, 2^31-1] of int:

public class T {
    public static void main(String[] args) {
        int a = Integer.parseInt(args[0]);
        float b = a;
        int c = a + 1;
        System.out.println(a == b && b == c && a != c);
    }
}
Similar behavior can be found if you replace int by long and float by double.

PHP: a fractal of bad design (fuzzy notepad)

Posted Apr 26, 2012 1:50 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

That's completely expected and correct behavior of equality comparisons involving floating point numbers. It's also noted in every textbook under the DO NOT USE category.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds