"Assume" directive for classes and methods


(D. Felipe Torres) #1

I've been reading the discussion in "Final by default for classes and
methods" and although I don't have a strong position towards what the
default behaviour should be, I think a directive to change that behaviour
should be added as when nullability was introduced into Obj-C.

In the current model of Swift, where methods and classes are not final we
can ease that by doing something like this:

ASSUME_FINAL_BEGIN

class MyClass {

    func aMethod(arg: String) {

    }

    func anotherMethod(number: Int) {

    }

}

ASSUME_FINAL_END

In this example the whole class is treated as final by the compiler.
On the other hand, in the following example:

class MyClass {

ASSUME_FINAL_BEGIN

    func aMethod(arg: String) {

    }

ASSUME_FINAL_END

    func anotherMethod(number: Int) {

    }

}

Only aMethod is final, leaving the rest to the default behaviour. (Ok, the
example is not different to prepending 'final' but you get the idea).

Similarly, should the classes and methods become final by default, a
directive to do the opposite should be added
(ASSUME_OVERRIDEABLE_(BEGIN|END)?)

···

--
++++++++++++++++++++++++++
Diego Torres.


(Joe Groff) #2

We tried to avoid these kinds of contextual blocks because they make reading declarations in isolation much harder. That's one of the reasons we have 'public'/'private' as per-decl modifiers rather than C++/ObjC-style grouping.

-Joe

···

On Dec 23, 2015, at 7:36 AM, D. Felipe Torres via swift-evolution <swift-evolution@swift.org> wrote:

I've been reading the discussion in "Final by default for classes and methods" and although I don't have a strong position towards what the default behaviour should be, I think a directive to change that behaviour should be added as when nullability was introduced into Obj-C.

In the current model of Swift, where methods and classes are not final we can ease that by doing something like this:

ASSUME_FINAL_BEGIN
class MyClass {
    func aMethod(arg: String) {
        
    }
    
    func anotherMethod(number: Int) {
        
    }
}
ASSUME_FINAL_END

In this example the whole class is treated as final by the compiler.
On the other hand, in the following example:

class MyClass {
ASSUME_FINAL_BEGIN
    func aMethod(arg: String) {
        
    }
ASSUME_FINAL_END
    func anotherMethod(number: Int) {
        
    }
}

Only aMethod is final, leaving the rest to the default behaviour. (Ok, the example is not different to prepending 'final' but you get the idea).

Similarly, should the classes and methods become final by default, a directive to do the opposite should be added (ASSUME_OVERRIDEABLE_(BEGIN|END)?)


(Jordan Rose) #3

One of the primary reasons we have the "regions" in Objective-C is because we have existing large bodies of code that need to be audited and annotated. The intent there is to set up a reasonable default, and just mark that a particular section follows that default, rather than to have some code inside regions and some code outside.

Jordan

···

On Dec 23, 2015, at 9:14 , Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 23, 2015, at 7:36 AM, D. Felipe Torres via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've been reading the discussion in "Final by default for classes and methods" and although I don't have a strong position towards what the default behaviour should be, I think a directive to change that behaviour should be added as when nullability was introduced into Obj-C.

In the current model of Swift, where methods and classes are not final we can ease that by doing something like this:

ASSUME_FINAL_BEGIN
class MyClass {
    func aMethod(arg: String) {
        
    }
    
    func anotherMethod(number: Int) {
        
    }
}
ASSUME_FINAL_END

In this example the whole class is treated as final by the compiler.
On the other hand, in the following example:

class MyClass {
ASSUME_FINAL_BEGIN
    func aMethod(arg: String) {
        
    }
ASSUME_FINAL_END
    func anotherMethod(number: Int) {
        
    }
}

Only aMethod is final, leaving the rest to the default behaviour. (Ok, the example is not different to prepending 'final' but you get the idea).

Similarly, should the classes and methods become final by default, a directive to do the opposite should be added (ASSUME_OVERRIDEABLE_(BEGIN|END)?)

We tried to avoid these kinds of contextual blocks because they make reading declarations in isolation much harder. That's one of the reasons we have 'public'/'private' as per-decl modifiers rather than C++/ObjC-style grouping.


(Tino) #4

I've been reading the discussion in "Final by default for classes and methods" and although I don't have a strong position towards what the default behaviour should be, I think a directive to change that behaviour should be added as when nullability was introduced into Obj-C.

In the current model of Swift, where methods and classes are not final we can ease that by doing something like this:

ASSUME_FINAL_BEGIN
class MyClass {
    func aMethod(arg: String) {
        
    }
    
    func anotherMethod(number: Int) {
        
    }
}
ASSUME_FINAL_END

I talked about this possibility in the thread you mention, and there are imho several other issues that could be addressed in a similar way:
[swift-evolution] [Pitch] make @noescape the default
[swift-evolution] Make non-void functions @warn_unused_result by default

But there would be one big downside:
All this fruitless arguing about better defaults keeps amateurs like me busy — just imagine the havoc I'd cause in the complicated and important topics :wink:

Best regards,
Tino


(Tino) #5

We tried to avoid these kinds of contextual blocks because they make reading declarations in isolation much harder. That's one of the reasons we have 'public'/'private' as per-decl modifiers rather than C++/ObjC-style grouping.

Imho that is no problem when the effect of the modifier isn't local.
In the case of final, it would only make a difference in a subclass, and no matter if that subclass is in the same module or in a different one, I don't see problems:
- If it's in the same module, the author most likely knows his own preference, so it's better to leave him the freedom of choice instead of forcing him to live with the global default.
- If it's in another module, there is the interface that is generated and has the information

Best regards,
Tino