Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: static methods in classes #2376

Closed
catamorphism opened this issue May 11, 2012 · 12 comments
Closed

RFC: static methods in classes #2376

catamorphism opened this issue May 11, 2012 · 12 comments
Labels
A-codegen Area: Code generation A-type-system Area: Type system
Milestone

Comments

@catamorphism
Copy link
Contributor

When discussing #2290 with @nikomatsakis and @pcwalton , we agreed that static methods might potentially be useful in classes. One of the motivating cases is to simplify how constructors get treated. We could even eliminate class constructors altogether, and write something like:

class cat {

  let name: str;
  let meow_count: uint;

  /* Requires a self parameter */
  fn meow() { ... }

  /* Doesn't require a self parameter */
  static fn cat(name: str) -> cat {
     cat{ name: name, meow_count: 0u } 
  }

}

In this case, there's no constructor, but rather, a static method called cat that returns a new instance of the class cat. I'm also assuming that a version of record initialization syntax could be used for classes, which doesn't work right now, but could be made to work. Since classes are nominal, we would need to prefix the record literal with the class name; this would decouple whatever other computation a constructor needs to do from the act of actually allocating a new record and filling in the class fields.

So I'm proposing to:

  • add a static modifier on function items, only valid within a class declaration, whose semantics are that a function declared as static fn f... requires no self argument and cannot refer to self in its body -- however, f can refer to class-private fields in its enclosing class.
  • add syntax to call static methods in a class C with the C:: prefix: as in, cat::cat() above (This is up for discussion -- I don't care how the exact syntax looks)
  • allow a nominal version of record initialization syntax to be used to create class literals

Notice that this removes the need for @class (as in the original spec, #1726) because you can now write a static method that takes an explicit self parameter.

@ghost ghost assigned catamorphism May 11, 2012
@catamorphism
Copy link
Contributor Author

(n.b. -- The problem with the syntax I suggested in the second bullet point is that this means you can't have both a type (specifically a class type) and a module named cat, which violates our principle that types and modules are separate namespaces. One option is to make an exception for classes, and consider every class name to be both a type name and a module name, but I'm open to other suggestions...)

@catamorphism
Copy link
Contributor Author

@pcwalton suggested an alternative to the entire plan, which would be to implement C++-style friend classes (or friend modules, in our case), which would allow you to write code that could access a different class's private fields, obviating the need for static functions.

@brson
Copy link
Contributor

brson commented May 11, 2012

I haven't followed this discussion, but if it's primarily a way to make ctors then I'm tentatively not in favor. It sounds very similar to our old way of creating obj constructors (just create a function and call it the constructor) which I found not terribly convenient to use.

@catamorphism
Copy link
Contributor Author

@brson It's not primarily a way to make ctors -- that was just an example (my fault for giving that too much weight). It arose because we were talking about #2290 and if we had static fns, we wouldn't need the special @class syntax -- because we could write functions that take a self parameter explicitly that are allowed to modify its private fields. Is that clear? I know it's a slightly subtle point.

@pcwalton
Copy link
Contributor

I prefer static methods to friends for the reason @brson gave, as well as the fact that having to make every class with private fields have a friend would be burdensome.

@brson
Copy link
Contributor

brson commented May 11, 2012

@catamorphism I'm going to show my ignorance regarding classes. Does @class just mean a boxed class instance, and are we proposing not being able to construct classes directly into boxes?

So regardless of the details I would like class constructors to avoid the following pattern:

ctor() {

    let field1 = do some work to build field1;
    ...
    let field2 = etc.

    // Now glue everything together!
    {
        field1: field1,
        field2: field2
    }

}

It sounds like this is what we're looking at, where you do all the imperative, stateful work in one phase, then build a giant record containing the results of that work. It's a common pattern in Rust, but it's not a common pattern in class constructors in most languages, where you are free to build up the fields over the course of the constructor. It's a lot of boilerplate.

@nikomatsakis
Copy link
Contributor

@brson an @class was supposed to be one that could only be in a box

@catamorphism
Copy link
Contributor Author

@brson @class is exactly like wrapping the result of a ctor in an @, but the only reason it has to be different from class is that in an @class, a method can return self or store it in a data structure (since self is guaranteed to be heap-allocated), whereas in a class, self isn't first-class (it can only be on the LHS of a field access or method call).

Also, if we add static fns, we can still keep ctors as a separate thing; the real point of static fns is to allow writing fns that take their self argument explicitly, but can access class-private members. I erred by over-focusing on the ctor example.

@pcwalton
Copy link
Contributor

So I was thinking again and there are a couple of arguments in favor of static functions that mean (IMHO) that we shouldn't shoot them down so quickly:

  • It allows constructors to fail in an in-band way without failing the task, by returning a result. This could be very important.
  • It allows classes to have multiple constructors. Almost all OO languages I know of have some facility for this.

We could sidestep the name resolution problems by having the record literal syntax for class construction be module-private by default, and not having static functions per se at all. This is a little hokey, but the more I think about it the more I think it isn't terrible; you can make other things be module-private, so why not constructors?

@catamorphism
Copy link
Contributor Author

@pcwalton I don't think it's that hokey. It wouldn't really be that the record literal syntax is module-private -- it would be that the literal constructor (C in C{x: 5, y: 7}, to use a strawperson syntax) is module-private. It would just fall out of that that the literal syntax would be module-private, since you can't write the literal syntax without a constructor name.

@Dretch
Copy link
Contributor

Dretch commented May 26, 2012

I think module-private constructors would be useful.

@catamorphism
Copy link
Contributor Author

Closing for now because max/min classes address this.

@catamorphism catamorphism removed their assignment Jun 16, 2014
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 22, 2022
celinval pushed a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation A-type-system Area: Type system
Projects
None yet
Development

No branches or pull requests

5 participants