Remix.run Logo
wk_end 3 days ago

I find the problem of ad hoc polymorphism so interesting. It’s clearly a desirable feature, but we’ve been trying for nearly fifty years and still don’t have a solution that everyone’s unambiguously happy with. Compare that to, like, lexical scoping or parametric polymorphism, which most languages just have by default at this point. They’re almost mathematical facts.

And you’d hope there’d be a way to do it. Parametric polymorphism feels underpowered if you can’t make any assumptions about the things you’re abstracting over. But it might be a Halting Problem-esque situation.

FWIW if a real, near-trade-off-free solution exists, I think it’ll require a bit of a Copernican revolution in how we approach things. I don’t have any real insight to offer there.

untilted 3 days ago | parent | next [-]

> Compare that to, like, lexical scoping or parametric polymorphism, which most languages just have by default at this point. They’re almost mathematical facts.

FWIW emacs lisp (in)famously still defaults to dynamic scoping -- there's been a proposal to change that default earlier this month but interestingly, there's still pushback. See e.g. https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00...

dan-robertson 3 days ago | parent | next [-]

At one time it was thought that implementing lexical scoping for a lisp (with lambdas, etc) was not possible to do performantly and this is one of the reasons that lots of lisps had dynamic scoping. That said, scheme has lexical scoping and I think that predates GNU Emacs by a reasonable amount of time.

kreetx 3 days ago | parent | prev [-]

AFAIK, dynamic scoping is still the default because of compatibility: older extensions might rely on it. For any new extension, the author should turn it on from the get go.

dominicrose 3 days ago | parent | prev [-]

Without a hierarchy, a class is just a group of functions that have a same first implicit argument called this. But what if a file was a namespace? (i.e. a javascript/typescript module) Then we can just create functions and they automatically belong to a group. One or multiple constants and variables can contain the data.

But do we need a hierarchy let alone multi-inheritance/traits if we just know what function to call and what file to import it from? Isn't that the job of interfaces? Isn't composition better than inheritance?

ninalanyon 3 days ago | parent | next [-]

Sounds like Nim. Nim doesn't have objects but it has something it calls universal function call syntax/uniform call syntax which lets you prefix a function call with the first argument instead of putting it in the argument list. This makes it look like object oriented coding without having to put the structure definition in the same file as the methods that act on it. This means that new methods can be added without having to edit the source of the structure or inherit from it.

wk_end 3 days ago | parent [-]

If I’m writing a hash map module that’s generic over what it accepts, and later someone else is going to want to use it with Foo keys, how am I able to write my hash map such that the hash function for Foos are in scope in my hash map module?

archargelod 3 days ago | parent [-]

With function overloading, templates and late static binding.

You just use a `hash` function in your library code and user has to implement a version of it that accepts the Foo type.

To resolve the scope problem, Nim uses templates[1] and a `mixin`[2] statement to bind user-defined hash procedure.

0 - https://github.com/nim-lang/Nim/lib/pure/collections/tables....

1 - https://github.com/nim-lang/Nim/blob/652edb229ae3ca736b19474...

2 - https://nim-lang.org/docs/manual.html#generics-mixin-stateme...

bhawks 3 days ago | parent | prev [-]

Files exist in a different universe of abstractions from language features. Heck a language should work in a universe where files don't exist at all.

A file is a stream of bytes that a process can get by giving the os a string (name) that has all sorts of encoding/decoding rules that rely on runtime state.

enugu 3 days ago | parent [-]

Sure, files are a detail. But, the concept of namespace doesn't need to be attached to a file, it can just be a convenient convention to attach a namespace to a file. In live environments like Smalltalk images, there are no files.

I think what /u/dominicrose is trying to get at was that OOP bundles together things which need not be and in doing so, one loses flexibility. OOP is Encapsulation(can also be done via namespaces/modules), Polymorphism(can be done by functions with a dispatch based on first argument) and Reuse/Extensibility(inheritance is a special case, there are many other ways to build a new class/data-type from older ones, composition being one).

Often, this is not recognized in discourse and we end up with a 'OOP vs FP' discussion [1] even though the issue is not im/mutability. In fact, the discussion in article of [1] is actually about what is being discussed in this article. Should one do polymorphism via named implementations like in ML or anonymous ones like in Haskell/Rust? Inheritance in standard OOP languages counts as named implementations as the subclass has a name. Named implementations require more annotation but also have certain advantages like more clarity in which implementation to use and don't expose type parameters to user of the library (which happens with typeclasses).

[1] https://news.ycombinator.com/item?id=41901577

igouy 2 days ago | parent [-]

> In live environments like Smalltalk images, there are no files.

Of course there are: image file, sources file, changes file.

And, of course, fileOuts to share code with others and to archive code -- so we can have a reproducible build process.

enugu 2 days ago | parent [-]

OK, but files are external to the system. Within the Smalltalk environment, everything is an object and files are required as the ambient OS works with files. You can say that some objects within the environment, containing program source are playing the same role as source files in usual programming. Even there, one can have a richer interface than text/binary files.

igouy a day ago | parent [-]

Long ago, Smalltalk's lack of explicit support for important aspects of programming was recognised:

"Programs consist of modules. Modules provide the units to divide the functional and organizational responsibility within a program."

"An Overview of Modular Smalltalk"

https://dl.acm.org/doi/pdf/10.1145/62083.62095

enugu a day ago | parent [-]

Yes, I do agree with you - live image programming has to be composable/comprehensible/reproducible, and crucial state shouldn't be in anonymous objects. (I've even thinking of replacing mutable objects with with pure functions modifying a a tree of data). Types is another direction and the work on Strongtalk has proved influential for popular VMs.

But, we dont need to go back from objects to files, except for the purpose of interacting with the OS. Richer structures actually help comprehensibility. For instance, revision control operating at a structural level. UNIX would have much nicer, if something like nushell had been adopted from the beginning, and the 'little pieces' used to build the system worked on structured data.