JacquesCarette / Drasil

Generate all the things (focusing on research software)
https://jacquescarette.github.io/Drasil
BSD 2-Clause "Simplified" License
136 stars 25 forks source link

Questions about multiple constructors #3765

Open B-rando1 opened 3 weeks ago

B-rando1 commented 3 weeks ago

All of our languages except Python allow multiple constructors for an object. We should probably lay out a stance on whether GOOL allows multiple constructors.

As a side note, Julia encourages having constructors call other constructors (e.g. cascading up default values) when it makes sense. See here for an example. I don't think this idea works in other languages, so I'm assuming we don't need to worry about that in GOOL?

B-rando1 commented 3 weeks ago

We discussed in our meeting today that it's ok if some design decisions don't work in all languages. Based on that, it seems to me that the right choice is to allow multiple constructors in GOOL, but have the Python renderer throw an error if we give it multiple constructors. This is in line with our treatment of floats (also not supported by Python).

As another side note, this is one more reason why #3763 is a useful change: counting the number of constructors!

balacij commented 1 week ago

Using the @classmethod annotation on methods defined inside of classes is conventional for building alternative constructors in Python. Actually, those are technically named constructors, but reliant on a base library-provided annotation (arguably not a part of the language specification, but I don't really see it going anywhere...).

For example,

from math import cos, sin

class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y

  @classmethod
  def from_polar(c, radius, angle):
    return c(radius * cos(angle), radius * sin(angle))

r, a = 10, 0
p = Point.from_polar(r, a)

This is relevant to our recent discussion about the constructors and methods.

B-rando1 commented 1 week ago

Oh, that's interesting @balacij! I'm trying to think if there would be a way to take advantage of this functionality in GOOL.

Do we think this is a worthwhile change to make? Enabling named constructors in GOOL likely wouldn't be too big of a task (apart from a few discussions about semantics), but taking advantage of it in drasil-code might be tricky.

balacij commented 4 days ago

I guess we can't call it a method, since it has the @classmethod annotation and it's called like a static method.

Yep, it is a class-level method (individual instances of the class do not have the @classmethods defined within them)! One note: @staticmethod differs from Python's @classmethod in one 'real' way: a @classmethod method has access to the class through the first parameter (i.e., self, except self refers to the class).

With our current structuring of constructors it would be difficult to make it work, as we would need to give a different name to each constructor. Getting unique names wouldn't be a problem, but keeping track of which name is used for each type signature would be.

Yep. This is really where we would need named constructors. Now that I think about it: I think that named constructors should be the default. They provide information about which constructor we really intended to call. Overloading can then be employed only when rendering into a language that supports it.

I suppose if we extended the functionality of constructors to allow named constructors (as you mentioned above and in our discussion of constructors and methods), we could probably make it work that way.

Yep!

Do we think this is a worthwhile change to make? Enabling named constructors in GOOL likely wouldn't be too big of a task (apart from a few discussions about semantics), but taking advantage of it in drasil-code might be tricky.

If it's not too much work on GOOL's side, I think it would be a great idea! Do we even have any instances of multiple constructors on the -code side? It might be useful to only have it one-sided for now?