<story><title>Pretending OOP Never Happened</title><url>https://www.johndcook.com/blog/2020/05/15/pretending-oop-never-happened/</url></story><parent_chain><item><author>uryga</author><text>if it&amp;#x27;s a function, what are the inputs&amp;#x2F;outputs? do you mean that in the way of &amp;quot;an object is a poor person&amp;#x27;s closure&amp;quot;?&lt;p&gt;in case anyone&amp;#x27;s unfamiliar, here&amp;#x27;s one basic way to emulate objects with closures. i think i saw it in SICP (?), reproducing it here because i just love how simple it is:&lt;p&gt;&lt;pre&gt;&lt;code&gt;  &amp;#x2F;&amp;#x2F; might be easier to first look at
  &amp;#x2F;&amp;#x2F; the usage example at the bottom

  let Point = (x, y) =&amp;gt; {
    let self = (message, args=null) =&amp;gt; {
      switch (message) {
        &amp;#x2F;&amp;#x2F; getters
        case &amp;#x27;x&amp;#x27;: return x;
        case &amp;#x27;y&amp;#x27;: return y;

        &amp;#x2F;&amp;#x2F; some operations
        &amp;#x2F;&amp;#x2F; (immutable, but that&amp;#x27;s not required)

        case &amp;#x27;toString&amp;#x27;:
          return `Point(x=${x}, y=${y})`;

        case &amp;#x27;move&amp;#x27;:
          let [dx, dy] = args;
          &amp;#x2F;&amp;#x2F; use our getters
          return Point(self(&amp;#x27;x&amp;#x27;)+dx, self(&amp;#x27;y&amp;#x27;)+dy);

        &amp;#x2F;&amp;#x2F; let&amp;#x27;s get DRY!
        case &amp;#x27;plus&amp;#x27;:
          let [other] = args;
          return self(&amp;#x27;move&amp;#x27;, other(&amp;#x27;x&amp;#x27;), other(&amp;#x27;y&amp;#x27;));

        default:
          throw Error(`unknown message: ${message} ${JSON.stringify(args)}`);
      }
    };
    return self;
  };
  
  
  let p1 = Point(3, 5);
  &amp;#x2F;&amp;#x2F; sending messages
  p1(&amp;#x27;x&amp;#x27;) === 3;
  p1(&amp;#x27;y&amp;#x27;) === 5;
  
  p1(&amp;#x27;move&amp;#x27;, [1, 2])(&amp;#x27;toString&amp;#x27;);
  &amp;#x2F;&amp;#x2F; --&amp;gt; &amp;quot;Point(x=4, y=7)&amp;quot;
  
  let p2 = Point(1, 2);
  p1(&amp;#x27;plus&amp;#x27;, [p2])(&amp;#x27;toString&amp;#x27;);
  &amp;#x2F;&amp;#x2F; --&amp;gt; &amp;quot;Point(x=4, y=7)&amp;quot;
  &lt;/code&gt;&lt;/pre&gt;
dynamic dispatch &amp;amp; message passing, just like that! and you can easily do `__getattr__&amp;#x2F;method_missing`-style dynamicism just by looking at `message`.&lt;p&gt;for the other way around, see how Java lambdas desugar to objects with a &amp;quot;call&amp;quot; method and closed-over variables as members.</text></item><item><author>ipnon</author><text>An object is in some ways a function that defines its own parameters (fields and methods) and arguments (state). This then is injected into another such function.</text></item><item><author>throwaway894345</author><text>These conversations aren&amp;#x27;t helped by the fact that OOP isn&amp;#x27;t well-defined, and observations about &amp;#x27;typical&amp;#x27; OOP--the banana that has a reference to the gorilla and transitively the entire jungle, or the pervasive abuse of inheritance--are &amp;quot;aren&amp;#x27;t really OOP and you can write bad code in any paradigm!&amp;quot; even though other paradigms (for whatever reason) don&amp;#x27;t share these issues at nearly the scale as OOP. Inheritance and god objects were certainly how OOP was taught at universities and in the predominate literature when I was in school circa 2010. And if these (mis)features aren&amp;#x27;t part of the definition of OOP, then what distinguishes it from functional and&amp;#x2F;or data oriented paradigms? Encapsulation? Seems like FP has encapsulation and DO is orthogonal. Certainly localization of state is common to both FP and DO--it&amp;#x27;s not an OOP innovation.&lt;p&gt;If OOP is so abstract as to be indistinguishable from other paradigms, then what value does it add?</text></item><item><author>commandlinefan</author><text>Usually when I see somebody arguing against object-oriented programming, I don&amp;#x27;t see them arguing for functional programming, but instead arguing for procedural (like Cobol, Basic, or Pascal) programming.  What they usually miss is that there&amp;#x27;s a reason procedural programming was abandoned some time around the mid-90&amp;#x27;s, and for good reason: you can&amp;#x27;t realistically develop useful software in pure-procedural way without introducing a lot of global state.  Even if you look at well-designed non-OO code like, say the Linux kernel, you&amp;#x27;ll see that there are object oriented concepts like information hiding and polymorphism all over the place; they just don&amp;#x27;t formalize them with the &amp;quot;class&amp;quot; or &amp;quot;private&amp;quot; keywords.  Unfortunately, what I see most programmers do is give up on OO design (and never even consider FP) and instead create global state that they call &amp;quot;singletons&amp;quot; to pretend that they didn&amp;#x27;t just create a global variable.  Because, as we all know, global variables are bad, but too few of us actually remember why.</text></item></parent_chain><comment><author>btilly</author><text>&lt;i&gt;do you mean that in the way of &amp;quot;an object is a poor person&amp;#x27;s closure&amp;quot;?&lt;/i&gt;&lt;p&gt;Objects are a poor man&amp;#x27;s closures.  And closures are a poor man&amp;#x27;s objects.&lt;p&gt;Modern languages have both.  And they serve different purposes.</text></comment>
<story><title>Pretending OOP Never Happened</title><url>https://www.johndcook.com/blog/2020/05/15/pretending-oop-never-happened/</url></story><parent_chain><item><author>uryga</author><text>if it&amp;#x27;s a function, what are the inputs&amp;#x2F;outputs? do you mean that in the way of &amp;quot;an object is a poor person&amp;#x27;s closure&amp;quot;?&lt;p&gt;in case anyone&amp;#x27;s unfamiliar, here&amp;#x27;s one basic way to emulate objects with closures. i think i saw it in SICP (?), reproducing it here because i just love how simple it is:&lt;p&gt;&lt;pre&gt;&lt;code&gt;  &amp;#x2F;&amp;#x2F; might be easier to first look at
  &amp;#x2F;&amp;#x2F; the usage example at the bottom

  let Point = (x, y) =&amp;gt; {
    let self = (message, args=null) =&amp;gt; {
      switch (message) {
        &amp;#x2F;&amp;#x2F; getters
        case &amp;#x27;x&amp;#x27;: return x;
        case &amp;#x27;y&amp;#x27;: return y;

        &amp;#x2F;&amp;#x2F; some operations
        &amp;#x2F;&amp;#x2F; (immutable, but that&amp;#x27;s not required)

        case &amp;#x27;toString&amp;#x27;:
          return `Point(x=${x}, y=${y})`;

        case &amp;#x27;move&amp;#x27;:
          let [dx, dy] = args;
          &amp;#x2F;&amp;#x2F; use our getters
          return Point(self(&amp;#x27;x&amp;#x27;)+dx, self(&amp;#x27;y&amp;#x27;)+dy);

        &amp;#x2F;&amp;#x2F; let&amp;#x27;s get DRY!
        case &amp;#x27;plus&amp;#x27;:
          let [other] = args;
          return self(&amp;#x27;move&amp;#x27;, other(&amp;#x27;x&amp;#x27;), other(&amp;#x27;y&amp;#x27;));

        default:
          throw Error(`unknown message: ${message} ${JSON.stringify(args)}`);
      }
    };
    return self;
  };
  
  
  let p1 = Point(3, 5);
  &amp;#x2F;&amp;#x2F; sending messages
  p1(&amp;#x27;x&amp;#x27;) === 3;
  p1(&amp;#x27;y&amp;#x27;) === 5;
  
  p1(&amp;#x27;move&amp;#x27;, [1, 2])(&amp;#x27;toString&amp;#x27;);
  &amp;#x2F;&amp;#x2F; --&amp;gt; &amp;quot;Point(x=4, y=7)&amp;quot;
  
  let p2 = Point(1, 2);
  p1(&amp;#x27;plus&amp;#x27;, [p2])(&amp;#x27;toString&amp;#x27;);
  &amp;#x2F;&amp;#x2F; --&amp;gt; &amp;quot;Point(x=4, y=7)&amp;quot;
  &lt;/code&gt;&lt;/pre&gt;
dynamic dispatch &amp;amp; message passing, just like that! and you can easily do `__getattr__&amp;#x2F;method_missing`-style dynamicism just by looking at `message`.&lt;p&gt;for the other way around, see how Java lambdas desugar to objects with a &amp;quot;call&amp;quot; method and closed-over variables as members.</text></item><item><author>ipnon</author><text>An object is in some ways a function that defines its own parameters (fields and methods) and arguments (state). This then is injected into another such function.</text></item><item><author>throwaway894345</author><text>These conversations aren&amp;#x27;t helped by the fact that OOP isn&amp;#x27;t well-defined, and observations about &amp;#x27;typical&amp;#x27; OOP--the banana that has a reference to the gorilla and transitively the entire jungle, or the pervasive abuse of inheritance--are &amp;quot;aren&amp;#x27;t really OOP and you can write bad code in any paradigm!&amp;quot; even though other paradigms (for whatever reason) don&amp;#x27;t share these issues at nearly the scale as OOP. Inheritance and god objects were certainly how OOP was taught at universities and in the predominate literature when I was in school circa 2010. And if these (mis)features aren&amp;#x27;t part of the definition of OOP, then what distinguishes it from functional and&amp;#x2F;or data oriented paradigms? Encapsulation? Seems like FP has encapsulation and DO is orthogonal. Certainly localization of state is common to both FP and DO--it&amp;#x27;s not an OOP innovation.&lt;p&gt;If OOP is so abstract as to be indistinguishable from other paradigms, then what value does it add?</text></item><item><author>commandlinefan</author><text>Usually when I see somebody arguing against object-oriented programming, I don&amp;#x27;t see them arguing for functional programming, but instead arguing for procedural (like Cobol, Basic, or Pascal) programming.  What they usually miss is that there&amp;#x27;s a reason procedural programming was abandoned some time around the mid-90&amp;#x27;s, and for good reason: you can&amp;#x27;t realistically develop useful software in pure-procedural way without introducing a lot of global state.  Even if you look at well-designed non-OO code like, say the Linux kernel, you&amp;#x27;ll see that there are object oriented concepts like information hiding and polymorphism all over the place; they just don&amp;#x27;t formalize them with the &amp;quot;class&amp;quot; or &amp;quot;private&amp;quot; keywords.  Unfortunately, what I see most programmers do is give up on OO design (and never even consider FP) and instead create global state that they call &amp;quot;singletons&amp;quot; to pretend that they didn&amp;#x27;t just create a global variable.  Because, as we all know, global variables are bad, but too few of us actually remember why.</text></item></parent_chain><comment><author>uryga</author><text>also, i just made a possibly interesting connection with JS methods (and their weirdness). in the above implementation, a message is first class, so you can send the same message to multiple objects:&lt;p&gt;&lt;pre&gt;&lt;code&gt;  let moveUp = [&amp;#x27;move&amp;#x27;, [0, 1]];
  p1(...moveUp)
  p2(...moveUp)
&lt;/code&gt;&lt;/pre&gt;
but you can&amp;#x27;t get a `move` that&amp;#x27;s &amp;quot;bound&amp;quot; to a particular object¹ – the &amp;quot;receiver&amp;quot; is decided when you &amp;quot;send&amp;quot; the message. which reminds me of how JS methods work: `this` is bound to what&amp;#x27;s &amp;quot;to the left of the dot&amp;quot; when you &lt;i&gt;call&lt;/i&gt; a method, so unlike Python,&lt;p&gt;&lt;pre&gt;&lt;code&gt;  obj.foo(1)
&lt;/code&gt;&lt;/pre&gt;
is not the same as&lt;p&gt;&lt;pre&gt;&lt;code&gt;  let f = obj.foo
  f(1) &amp;#x2F;&amp;#x2F; Error: &amp;#x27;this&amp;#x27; is undefined
&lt;/code&gt;&lt;/pre&gt;
maybe there&amp;#x27;s a connection to some language that inspired JS&amp;#x27; OO model, with prototypes and all that?&lt;p&gt;---&lt;p&gt;¹ well, unless you explicitly wrap it in another closure like&lt;p&gt;&lt;pre&gt;&lt;code&gt;  (args) =&amp;gt; p1(&amp;#x27;move&amp;#x27;, args)&lt;/code&gt;&lt;/pre&gt;</text></comment>