Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I thought that privileging the first argument of a function, which is all that separates a method from a function, was understood to be an ugly hack. I thought that this was acknowledged now, and only legacy languages are stuck with it. Julia, Rust and Go don't do this. So it's going out of fashion and becoming legacy.

IOW, there was never really a difference between

  obj f(obj);
and

  class obj {obj f();}
so the whole idea was a mistake.

Likewise,

  obj.f()
should be synonymous with

  f(obj)
and the fact that in some languages it's not is evidence of a poorly thought-out abstraction. See multiple dispatch for the death blow.

There's also a discussion elsewhere here about operator overloading, and how arithmetic operators don't behave like methods.



> I thought that privileging the first argument of a function, which is all that separates a method from a function, was understood to be an ugly hack. I thought that this was acknowledged now, and only legacy languages are stuck with it. Julia, Rust and Go don't do this. So it's going out of fashion and becoming legacy. [emphasis added]

What?

Go has methods which "privilege" the first argument to functions:

https://go.dev/tour/methods/1

  func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
  }
Though it moves the argument out of the argument list and between the func keyword and method name.

Rust also has a notion of methods:

https://doc.rust-lang.org/rust-by-example/fn/methods.html

Were you thinking of other languages?


In Go you can assign this "method" to a func(v Vertex) float64 and it will run just fine: https://go.dev/play/p/NBS4Fc3r0w-

It really is just syntax sugar,


You can have multiple `f` with different "arguments" (if you consider a receiver a part of arguments) without the full multimethod, which is actually pretty hard to get it right and only one language out of your examples (Julia) does that. Other two languages (Rust and Go) fully retain classes, slightly obscured to fit with traits and interfaces respectively.


obj.f() shouldn't necessarily be synonymous with f(obj) though. How would the latter case handle private fields, for example?


You'd use a module to hides things. Some OOP languages conflate modules (which do information-hiding) with private fields in classes. If you think that `obj.f()` and `f(obj)` should mean different things, then your reasoning is likely faulty.


> You'd use a module to hides things.

And than you need functors and existential types to recreate classes… ;-)

Your reasoning is likely faulty if you don't see that OOP is a very advanced and great module system.

The only problem with OOP is that it's often misused for other things that aren't modules. But that's a different story.


To clarify, I’m talking about private fields in each object/struct. You could say all functions defined in the same module get access to private struct fields. That works until you want a more specialized version of some of those functions — essentially, a different module that has access to protected fields.

Here’s another example. You’re writing a function `g` that accepts an object of type `Foo` and calls function `f` on it. You have a default implementation of `f`, but you also want to let the caller supply their own implementation. If you have some way of attaching behavior to a type — classes, typeclasses, etc — this is trivial. If not, your function has to explicitly ask for every single function from the caller.


> You'd use a module to hides things. Some OOP languages conflate modules (which do information-hiding) with private fields in classes.

And you can instantiate multiple instances of these "modules"?


You don't need multiple module instances, the modules just need access to details about the opaque type or private portions of a type. If you've ever seen this in a C header:

  struct foo;
That's an example of an opaque type. Put that in a header, and any function can make use of it in any other C file, they just can't access its innards (well, it's C so you actually can if you know how its contents are packed). Functions can accept them as parameters and return them knowing nothing but that opaque type and some additional function signatures like this (to do something useful with it):

  struct foo make_foo(...); // or struct foo*
  void print_foo(struct foo*); // or struct foo
So I can write something like this:

  // main.c
  #include "foo.h"
  // other includes
  void do_something(struct foo* f) {
    // lots of code
    print_foo(f);
  }
  int main(int argc, char* argv[]) {
    struct foo f = make_foo(a_param);
    do_something(&f);
    return 0;
  }
In a hypothetical C you could do something like this:

  struct foo {
    int a;
    char b;
    private;
  };
That last bit indicating that there is something there, but not what it is. Then somewhere you'd have a fuller definition:

  struct foo {
    int a;
    char b;
    // private expanded
    float c;
  }
Which would be used by functions which are meant to actually operate on the rest of this structure. In this case, anything that knows of struct foo can directly access its "public" fields of a and b, but have no clue about the remaining fields.


If you want to maintain both syntaxes and have there be some sort of equivalence between them, then I think think the type system should handle it. Where a type operator ‘private-access’ grants access to some objects private fields and then obj.f() == f(private-access obj).

Maybe this would be seen as a violation of encapsulation, but to make the two equivalent requires the ability to allow private variable access at the call cite.


The point is that they’re not equivalent. What’s the difference between your proposal and just not having private members at all?


From a mathematical point of view it can seem like that. But now pick a language like Nim, whcih also has a crazy regex to match symbol equality, and unigorm call syntax etc. and the IDE completions are much harder to find.


I wish I had your problems.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: