Why can't Swift instance methods call class methods without qualification?


(Rick M) #1

Why can my instance methods not call class methods without the class specifier?

class MyClass
{
   func
   foo()
   {
       classMethod()
   }

   class
   func
   classMethod()
   {
   }
}

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

···

--
Rick Mann
rmann@latencyzero.com


(Zhao Xin) #2

Just a choice made by the language designers to distinguish the call at the
call site.

You should be aware of using static methods as it may change static
variables, which affects all instances of that class. Normally I think
static methods is designed to use outside the class instance, if you have
to use it inside its instance method. You may need to rethink the pattern
you do.

Zhaoxin

···

On Fri, Jul 1, 2016 at 8:59 AM, Rick Mann via swift-users < swift-users@swift.org> wrote:

Why can my instance methods not call class methods without the class
specifier?

class MyClass
{
   func
   foo()
   {
       classMethod()
   }

   class
   func
   classMethod()
   {
   }
}

Why do I have to call MyClass.classMethod()? Just a choice made by the
language designers to distinguish the call at the call site? I like C++'s
way of treating all static methods as directly available to the instance.

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rick M) #3

As Jens was saying, an instance method can also mutate static variables, so they're just as "dangerous" as static methods. Being forced to prefix a static method call doesn't change that.

Even the argument that an instance method could have the same name as a static method doesn't seem to hold water. In fact, it seems like a terrible idea to allow, but I just tested it, and it is allowed. The problem is, you can never be sure what was intended in the method two(), below:

class Foo
{
    class
    func
    one()
    {
        print("class one()")
    }
    
    func
    one()
    {
        print("instance one()")
    }
    
    func
    two()
    {
        one()
    }
}

I think instead, this should generate a warning that there are two methods with the same name, and that as written, the instance method is being called. If there were no instance method one(), it would be unambiguous.

···

On Jul 1, 2016, at 10:25 , Nicholas Outram <nicholas.outram@me.com> wrote:

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code. Having the class prefix is a reminder and therefore requires additional synchronisation if it is to be invoked safely from multiple threads.

--
Rick Mann
rmann@latencyzero.com


(Brent Royal-Gordon) #4

There are two kinds of OO languages: ones with metatypes and ones without them.

Basically, in C++ a class is a thing that exists at compile-time. You can't create a variable that contains "a class" or pass "a class" to a function. RTTI gives you access to an object *describing* a class, but this is not the class itself, any more than a map of California is California.

In many other languages, including Swift, this is not the case. A class is itself an object that exists at runtime. The class object is an instance of a "metaclass", a second class which parallels the original class; its class/static members are actually metaclass instance members. That means you can get the class instance, assign it to variables, pass it around, call static methods on it, and call initializers on it to create new instances. You might think of it this way: Every class inherently comes with a singleton, which provides access to all static members and factory methods for all initializers.

(In Swift, which has non-object types, the terminology is actually a little different from normal: the "class object" is a "type instance", and the "metaclass" is a "metatype". A type `Foo` has a metatype called `Foo.Type`. You can retrieve any instance's type instance with `foo.dynamicType`, or retrieve a type's type instance with `Foo.self`.)

If you adopt this design, then treating instance methods and class methods as belonging to different namespaces is the most straightforward way to design the language. Instance methods belong to the class and are called on instances, while class methods belong to the metaclass and are called on class objects. You wouldn't expect `someFoo.bar()` to call a method on `Foo`'s class object any more than you would expect it to call a method on `someBaz`.

You *could* make that work, of course, but it would be wholly artificial. Languages which do put class and instance methods in the same namespace—C++, Perl, Python—usually do so because that falls out naturally from their own designs.

If the above was too dense and jargony:

1. Sorry.

2. This is common behavior in many OO languages. Off the top of my head, Ruby, Objective-C, and C# all behave the way Swift does.

3. This behavior falls naturally out of some very deep—and very desirable—features of Swift's design. If it were changed, the change would be a hack.

···

On Jun 30, 2016, at 5:59 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

--
Brent Royal-Gordon
Architechies


(Nicholas Outram) #5

I personally find the prefix to be consistent and safer.

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code. For me, having the class prefix is a reminder and therefore requires additional synchronisation if it is to be invoked safely from multiple threads.

Nick

···

On 1 Jul 2016, at 01:59, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why can my instance methods not call class methods without the class specifier?

class MyClass
{
  func
  foo()
  {
      classMethod()
  }

  class
  func
  classMethod()
  {
  }
}

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rick M) #6

Just a choice made by the language designers to distinguish the call at the call site.

You should be aware of using static methods as it may change static variables, which affects all instances of that class. Normally I think static methods is designed to use outside the class instance, if you have to use it inside its instance method. You may need to rethink the pattern you do.

I think of static methods as applying to all instances, and so code them to "behave properly" no matter how they're called (since I can't really control who calls it, unless it's my own class). Since it's implicitly obvious (to me) that I mean "this class" when I call one, I find it a bit tedious qualify the call with the class name.

It's fine, in the end, but I was curious why it was like this, and if there was a more obvious reason why it needed the qualification.

···

On Jun 30, 2016, at 18:47 , zh ao <owenzx@gmail.com> wrote:

Zhaoxin

On Fri, Jul 1, 2016 at 8:59 AM, Rick Mann via swift-users <swift-users@swift.org> wrote:
Why can my instance methods not call class methods without the class specifier?

class MyClass
{
   func
   foo()
   {
       classMethod()
   }

   class
   func
   classMethod()
   {
   }
}

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Rick Mann
rmann@latencyzero.com


(David Sweeris) #7

I'm pretty sure you can have instance and static methods with the same name. Requiring `Type.foo()` instead of just `foo()` would tell the compiler which one you want.

- Dave Sweeris

···

On Jun 30, 2016, at 21:01, Rick Mann via swift-users <swift-users@swift.org> wrote:

On Jun 30, 2016, at 18:47 , zh ao <owenzx@gmail.com> wrote:

Just a choice made by the language designers to distinguish the call at the call site.

You should be aware of using static methods as it may change static variables, which affects all instances of that class. Normally I think static methods is designed to use outside the class instance, if you have to use it inside its instance method. You may need to rethink the pattern you do.

I think of static methods as applying to all instances, and so code them to "behave properly" no matter how they're called (since I can't really control who calls it, unless it's my own class). Since it's implicitly obvious (to me) that I mean "this class" when I call one, I find it a bit tedious qualify the call with the class name.

It's fine, in the end, but I was curious why it was like this, and if there was a more obvious reason why it needed the qualification.

Zhaoxin

On Fri, Jul 1, 2016 at 8:59 AM, Rick Mann via swift-users <swift-users@swift.org> wrote:
Why can my instance methods not call class methods without the class specifier?

class MyClass
{
  func
  foo()
  {
      classMethod()
  }

  class
  func
  classMethod()
  {
  }
}

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jens Alfke) #8

This doesn’t make any sense to me. All class-based OO languages have static/class methods, so this isn’t specific to Swift. And any method can change static class variables. There’s nothing special about static methods that makes them less suitable for use by instance methods.

—Jens

···

On Jun 30, 2016, at 6:47 PM, zh ao via swift-users <swift-users@swift.org> wrote:

You should be aware of using static methods as it may change static variables, which affects all instances of that class. Normally I think static methods is designed to use outside the class instance, if you have to use it inside its instance method. You may need to rethink the pattern you do.


(Jens Alfke) #9

This is the same argument zh ao made. But instance methods may also mutate static variables, so the fact that you’re calling a class method doesn’t make the call any more dangerous.

Moreover, mutating instance variables can be just as dangerous for multithreaded code (and is a more frequent source of bugs IMHO).

Really, the only significant difference is that a class method can’t modify instance variables, so from that perspective it’s actually a bit safer than an instance method call!

—Jens

···

On Jul 1, 2016, at 10:28 AM, Nicholas Outram via swift-users <swift-users@swift.org> wrote:

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code.


(Kate Stone) #10

Though that isn’t strictly true for singleton patterns and other reasons why class variables might include references to instances.

I believe there’s real value in being explicit about referencing class members. It helps both the reader of the code and it makes writing code with typical IDE conveniences like code completion less cluttered and more informative. Unfamiliar class methods won’t be included in lists of suggestions where they might look like they operate on the current instance.

Kate Stone k8stone@apple.com <mailto:k8stone@apple.com>
 Xcode Low Level Tools

···

On Jul 1, 2016, at 11:01 AM, Jens Alfke via swift-users <swift-users@swift.org> wrote:

On Jul 1, 2016, at 10:28 AM, Nicholas Outram via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code.

This is the same argument zh ao made. But instance methods may also mutate static variables, so the fact that you’re calling a class method doesn’t make the call any more dangerous.

Moreover, mutating instance variables can be just as dangerous for multithreaded code (and is a more frequent source of bugs IMHO).

Really, the only significant difference is that a class method can’t modify instance variables, so from that perspective it’s actually a bit safer than an instance method call!


(Kerry Hazelgren) #11

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code.

This is the same argument zh ao made. But instance methods may also mutate static variables, so the fact that you’re calling a class method doesn’t make the call any more dangerous.

Moreover, mutating instance variables can be just as dangerous for multithreaded code (and is a more frequent source of bugs IMHO).

Really, the only significant difference is that a class method can’t modify instance variables, so from that perspective it’s actually a bit safer than an instance method call!

Though that isn’t strictly true for singleton patterns and other reasons why class variables might include references to instances.

I believe there’s real value in being explicit about referencing class members. It helps both the reader of the code and it makes writing code with typical IDE conveniences like code completion less cluttered and more informative. Unfamiliar class methods won’t be included in lists of suggestions where they might look like they operate on the current instance.

I agree. I think that removing the class specifier provides a bit of simplicity but at the cost of ambiguity, which is decidedly not swift-y.

Kerry

···

On Jul 1, 2016, at 11:06 AM, Kate Stone via swift-users <swift-users@swift.org> wrote:

On Jul 1, 2016, at 11:01 AM, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Jul 1, 2016, at 10:28 AM, Nicholas Outram via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Kate Stone k8stone@apple.com <mailto:k8stone@apple.com>
 Xcode Low Level Tools

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Zhao Xin) #12

Swift has its own suggested patterns on calling methods. For example, it
suggests you calling instance methods directly inside class. It also forces
you calling self.method() in closure that without @noescape. As well as the
static method with the class name in your question. Those are different
from C++. But it does differ the differences between methods.

Zhaoxin

···

On Fri, Jul 1, 2016 at 10:01 AM, Rick Mann <rmann@latencyzero.com> wrote:

> On Jun 30, 2016, at 18:47 , zh ao <owenzx@gmail.com> wrote:
>
> Just a choice made by the language designers to distinguish the call at
the call site.
>
> You should be aware of using static methods as it may change static
variables, which affects all instances of that class. Normally I think
static methods is designed to use outside the class instance, if you have
to use it inside its instance method. You may need to rethink the pattern
you do.

I think of static methods as applying to all instances, and so code them
to "behave properly" no matter how they're called (since I can't really
control who calls it, unless it's my own class). Since it's implicitly
obvious (to me) that I mean "this class" when I call one, I find it a bit
tedious qualify the call with the class name.

It's fine, in the end, but I was curious why it was like this, and if
there was a more obvious reason why it needed the qualification.

>
> Zhaoxin
>
> On Fri, Jul 1, 2016 at 8:59 AM, Rick Mann via swift-users < > swift-users@swift.org> wrote:
> Why can my instance methods not call class methods without the class
specifier?
>
> class MyClass
> {
> func
> foo()
> {
> classMethod()
> }
>
> class
> func
> classMethod()
> {
> }
> }
>
> Why do I have to call MyClass.classMethod()? Just a choice made by the
language designers to distinguish the call at the call site? I like C++'s
way of treating all static methods as directly available to the instance.
>
> --
> Rick Mann
> rmann@latencyzero.com
>
>
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>

--
Rick Mann
rmann@latencyzero.com


(Jens Alfke) #13

Sure you can. It’s easy to tell that it calls the instance method, because if it were calling the class method there would have to be a “Foo.” in front of it.

You’re first arguing that class-method calls should have the same syntax as instance-method calls, and then complaining that having class and instance methods with the same name is ambiguous … but the reason for the ambiguity is because they’d be hard to tell apart using your proposed syntax. That’s not coherent.

—Jens

···

On Jul 1, 2016, at 2:02 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

The problem is, you can never be sure what was intended in the method two(), below:


(Rick M) #14

Hmm. It sounds like you're saying it is the way it is as a side-effect of the language implementation.

Maybe it's just my C++ upbringing, but it seems very counter-intuitive to me. A class method and an instance method look very much the same: they're defined in the same place (inside a class), and differ only in the "class" keyword. Sure, the class method can't access the instance variables, but it seems very, very natural that the instance can access the class, because the knowledge is available right there (either the implicit "self" or the instance variable used to call the method both have an obvious type).

In the same way that "self" is implicit in front of a method call from within the class, so to should be the class name in front of a class method call. That to me is consistent not only with Swift, but with other languages.

I've always found it annoying that Objective-C couldn't do this, either, but it has so many weirdnesses I just chocked it up as yet another.

···

On Jul 1, 2016, at 15:17 , Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 30, 2016, at 5:59 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why do I have to call MyClass.classMethod()? Just a choice made by the language designers to distinguish the call at the call site? I like C++'s way of treating all static methods as directly available to the instance.

There are two kinds of OO languages: ones with metatypes and ones without them.

Basically, in C++ a class is a thing that exists at compile-time. You can't create a variable that contains "a class" or pass "a class" to a function. RTTI gives you access to an object *describing* a class, but this is not the class itself, any more than a map of California is California.

In many other languages, including Swift, this is not the case. A class is itself an object that exists at runtime. The class object is an instance of a "metaclass", a second class which parallels the original class; its class/static members are actually metaclass instance members. That means you can get the class instance, assign it to variables, pass it around, call static methods on it, and call initializers on it to create new instances. You might think of it this way: Every class inherently comes with a singleton, which provides access to all static members and factory methods for all initializers.

(In Swift, which has non-object types, the terminology is actually a little different from normal: the "class object" is a "type instance", and the "metaclass" is a "metatype". A type `Foo` has a metatype called `Foo.Type`. You can retrieve any instance's type instance with `foo.dynamicType`, or retrieve a type's type instance with `Foo.self`.)

If you adopt this design, then treating instance methods and class methods as belonging to different namespaces is the most straightforward way to design the language. Instance methods belong to the class and are called on instances, while class methods belong to the metaclass and are called on class objects. You wouldn't expect `someFoo.bar()` to call a method on `Foo`'s class object any more than you would expect it to call a method on `someBaz`.

You *could* make that work, of course, but it would be wholly artificial. Languages which do put class and instance methods in the same namespace—C++, Perl, Python—usually do so because that falls out naturally from their own designs.

If the above was too dense and jargony:

1. Sorry.

2. This is common behavior in many OO languages. Off the top of my head, Ruby, Objective-C, and C# all behave the way Swift does.

3. This behavior falls naturally out of some very deep—and very desirable—features of Swift's design. If it were changed, the change would be a hack.

--
Rick Mann
rmann@latencyzero.com


(Zhao Xin) #15

Swift forces you to use class name to alert you on the fact that static
variables and methods (may) affect the other instances of the class as
static variables are shared between instances. That does make sense.

Zhaoxin

···

On Fri, Jul 1, 2016 at 11:57 PM, Jens Alfke <jens@mooseyard.com> wrote:

On Jun 30, 2016, at 6:47 PM, zh ao via swift-users <swift-users@swift.org> > wrote:

You should be aware of using static methods as it may change static
variables, which affects all instances of that class. Normally I think
static methods is designed to use outside the class instance, if you have
to use it inside its instance method. You may need to rethink the pattern
you do.

This doesn’t make any sense to me. All class-based OO languages have
static/class methods, so this isn’t specific to Swift. And *any* method
can change static class variables. There’s nothing special about static
methods that makes them less suitable for use by instance methods.

—Jens


(Nicholas Outram) #16

You are right of course.

I'm looking at this more from the eyes of an educator, where anything that reduces ambiguity helps. Students naively gravitating towards a singleton pattern is one of the battles I face. Some learners don't even properly understand the difference or risks.
Invoking a static method can only mutate shared memory, making it a simple candidate for dangerous practise, so it's helpful when a language is explicit.

Ultimately you are right of course, as you say, instance methods can do this also.
(Maybe it's also my own personal style / bias as I tend to avoid referencing static variables from instance methods where possible)

Good discussion!

···

Sent from my iPad

On 1 Jul 2016, at 19:01, Jens Alfke <jens@mooseyard.com> wrote:

On Jul 1, 2016, at 10:28 AM, Nicholas Outram via swift-users <swift-users@swift.org> wrote:

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code.

This is the same argument zh ao made. But instance methods may also mutate static variables, so the fact that you’re calling a class method doesn’t make the call any more dangerous.

Moreover, mutating instance variables can be just as dangerous for multithreaded code (and is a more frequent source of bugs IMHO).

Really, the only significant difference is that a class method can’t modify instance variables, so from that perspective it’s actually a bit safer than an instance method call!

—Jens


(Nicholas Outram) #17

Good point.

Again, from an educator perspective, one view is to think of the Class itself as a singleton object in memory, with its own set of iVars and methods that operate upon them. Although declared and defined in one source, when you visualise as objects / relationships in memory, one model is to see each instance as a small island with references back to a common shared singleton object (the class).
The prefix seems consistent with this model.

Now this may / may not match reality, but I find it's helpful to have that clear separation, especially for new learners, and Swift is a good entry language in this respect.
(Similarly I like the way closures sometimes force the developer to use the self prefix as well).

···

Sent from my iPad

On 1 Jul 2016, at 19:06, Kate Stone <k8stone@apple.com> wrote:

On Jul 1, 2016, at 11:01 AM, Jens Alfke via swift-users <swift-users@swift.org> wrote:

On Jul 1, 2016, at 10:28 AM, Nicholas Outram via swift-users <swift-users@swift.org> wrote:

class methods may mutate "mutable static variables” (singletons), which are dangerous in multi-threaded code.

This is the same argument zh ao made. But instance methods may also mutate static variables, so the fact that you’re calling a class method doesn’t make the call any more dangerous.

Moreover, mutating instance variables can be just as dangerous for multithreaded code (and is a more frequent source of bugs IMHO).

Really, the only significant difference is that a class method can’t modify instance variables, so from that perspective it’s actually a bit safer than an instance method call!

Though that isn’t strictly true for singleton patterns and other reasons why class variables might include references to instances.

I believe there’s real value in being explicit about referencing class members. It helps both the reader of the code and it makes writing code with typical IDE conveniences like code completion less cluttered and more informative. Unfamiliar class methods won’t be included in lists of suggestions where they might look like they operate on the current instance.

Kate Stone k8stone@apple.com
 Xcode Low Level Tools


(Jens Alfke) #18

I disagree. Both static and instance methods can affect other instances of the class. In other words, just looking at these two calls:
  something()
  MyClass.something()
there’s no way to tell whether either or both of them change class-wide state. (To spell it out clearly: the implementation of the instance method something() might change the variable MyClass.staticState.)

I think the reasoning behind this syntax is simply to make it easy to distinguish usages of static members (methods or variables) from instance ones.

—Jens

···

On Jul 1, 2016, at 9:38 AM, zh ao <owenzx@gmail.com> wrote:

Swift forces you to use class name to alert you on the fact that static variables and methods (may) affect the other instances of the class as static variables are shared between instances. That does make sense.


(Dan Loewenherz) #19

I agree. If not for this rule, the compiler would need to enforce
uniqueness across type and instance method names. There’s no other way
to disambiguate which function you’re trying to call.

Also, keep in mind that something() is syntactic sugar for
self.something(), which itself is syntactic sugar for
MyClass.something(self)().

If the compiler allowed you to skip MyClass and let you use
something() to reference the type method, how can it know that you
mean MyClass.something() and not MyClass.something(self)()? Since both
functions accept different parameters this behavior would be undefined
and you would be unable to use the same name for a type method and
instance method on the same type.

Dan

···

On Fri, Jul 1, 2016 at 11:58 AM, Jens Alfke via swift-users <swift-users@swift.org> wrote:

> On Jul 1, 2016, at 9:38 AM, zh ao <owenzx@gmail.com> wrote:
>
> Swift forces you to use class name to alert you on the fact that static variables and methods (may) affect the other instances of the class as static variables are shared between instances. That does make sense.

I disagree. Both static and instance methods can affect other instances of the class. In other words, just looking at these two calls:
        something()
        MyClass.something()
there’s no way to tell whether either or both of them change class-wide state. (To spell it out clearly: the implementation of the instance method something() might change the variable MyClass.staticState.)

I think the reasoning behind this syntax is simply to make it easy to distinguish usages of static members (methods or variables) from instance ones.

—Jens


(Rick M) #20

Sure you can. It’s easy to tell that it calls the instance method, because if it were calling the class method there would have to be a “Foo.” in front of it.

I'm saying you can't tell what was *intended*, at least, not without knowing about this particular idiosyncrasy of the language. But someone coming from C++ (and I imagine there are many), might not notice this without a compiler warning.

Now, if in this case, you had to be specific (either Foo. or self.), it might be okay. But I certainly would not make the assumption that the author didn't want to call the class method, and if I made the mistake in coding it, I would never know that's why, if it failed in some subtle way.

You’re first arguing that class-method calls should have the same syntax as instance-method calls, and then complaining that having class and instance methods with the same name is ambiguous … but the reason for the ambiguity is because they’d be hard to tell apart using your proposed syntax. That’s not coherent.

I'm saying first and foremost that it should not be allowed to have a class and an instance method with the same name. That should just be a compile-time error.

Second, I'm saying that you should be able to call a class method on an instance.

···

On Jul 1, 2016, at 14:28 , Jens Alfke <jens@mooseyard.com> wrote:

--
Rick Mann
rmann@latencyzero.com