[Idea] Add dynamicType casting


(Michael Henson) #1

Currently, the language syntax only allows type identifiers in the
type-casting-operator productions:

" " surrounds a keyword

type-casting-operator -> "is" type
type-casting-operator -> "as" type
type-casting-operator -> "as" "?" type
type-casting-operator -> "as" "!" type

The type production doesn't allow for expressions which resolve to a type,
only explicit type references.

So, if you want to refer to the item *as* its dynamic type, there's no
direct way to do that unless you declare the name of the type in code:

class Example {}
var value: Any = Example()
var again = value as value.dynamicType
// doesn't work because value.dynamicType is an expression

It should be possible to upcast to dynamicType immediately with no chance
of failure. To that end, I suggest adding two productions:

type-casting-operator -> "is" "dynamicType"
type-casting-operator -> "as" "dynamicType"

Following along the example above, we could then do:

var nowPossible = value as dynamicType

and have nowPossible be Example.Type.

Possible use cases for this functionality include:

1. Dealing with mixed-type collections from Objective-C code:
   @[ @"key1", @5, @"key2", @20, @"key3", @[@"red",@"green",@"blue"]]

2. Taking advantage of type-specific polymorphism without having to modify
code:

    func handleObject(obj: NSNumber) { print("Number") }
    func handleObject(obj: NSData) { print("Data") }

    func dispatchToHandler(kind: AnyObject) {
        print("dispatching \(kind.dynamicType)")
        handleObject(kind as dynamicType)
    }

I suspect that handling this use case might pose the most difficulties when
implementing the feature. It might make the whole thing impossible if
there's no way to resolve types at run-time in compiled code. For example,
if the dispatcher is in a Framework distributed as a binary and the user
does

class MyClass {}
func handleObject(obj: MyClass) { print "Success!" }

let stuff = MyClass()
dispatchToHandler(stuff)

in the project's code, what would happen?

Casting to an intermediate type between the static and dynamic types would
fall out naturally, though in that case you'd already have to know the
dynamicType and write the explicit intermediate type name in the code. If
that much is known then it's possible to cast directly to that intermediate
type with existing syntax.

Also, it's worth noting that the "Any" case is only the broadest instance
possible. Anything that passes data along as a super type, by using a
Protocol as a concrete type specifier, etc. could benefit from this
mechanism.

Mike


(Félix Cloutier) #2

func magic(_ variable: Any) {
  let foo = variable as dynamicType
  // ???
}

magic("hello")
magic(42)

What would be the result of this? What benefit do I get from casting it to its dynamic type?

Félix

···

Le 8 janv. 2016 à 23:40:46, Michael Henson via swift-evolution <swift-evolution@swift.org> a écrit :

Currently, the language syntax only allows type identifiers in the type-casting-operator productions:

" " surrounds a keyword

type-casting-operator -> "is" type
type-casting-operator -> "as" type
type-casting-operator -> "as" "?" type
type-casting-operator -> "as" "!" type

The type production doesn't allow for expressions which resolve to a type, only explicit type references.

So, if you want to refer to the item *as* its dynamic type, there's no direct way to do that unless you declare the name of the type in code:

class Example {}
var value: Any = Example()
var again = value as value.dynamicType
// doesn't work because value.dynamicType is an expression

It should be possible to upcast to dynamicType immediately with no chance of failure. To that end, I suggest adding two productions:

type-casting-operator -> "is" "dynamicType"
type-casting-operator -> "as" "dynamicType"

Following along the example above, we could then do:

var nowPossible = value as dynamicType

and have nowPossible be Example.Type.

Possible use cases for this functionality include:

1. Dealing with mixed-type collections from Objective-C code:
   @[ @"key1", @5, @"key2", @20, @"key3", @[@"red",@"green",@"blue"]]

2. Taking advantage of type-specific polymorphism without having to modify code:

    func handleObject(obj: NSNumber) { print("Number") }
    func handleObject(obj: NSData) { print("Data") }

    func dispatchToHandler(kind: AnyObject) {
        print("dispatching \(kind.dynamicType)")
        handleObject(kind as dynamicType)
    }

I suspect that handling this use case might pose the most difficulties when implementing the feature. It might make the whole thing impossible if there's no way to resolve types at run-time in compiled code. For example, if the dispatcher is in a Framework distributed as a binary and the user does

class MyClass {}
func handleObject(obj: MyClass) { print "Success!" }

let stuff = MyClass()
dispatchToHandler(stuff)

in the project's code, what would happen?

Casting to an intermediate type between the static and dynamic types would fall out naturally, though in that case you'd already have to know the dynamicType and write the explicit intermediate type name in the code. If that much is known then it's possible to cast directly to that intermediate type with existing syntax.

Also, it's worth noting that the "Any" case is only the broadest instance possible. Anything that passes data along as a super type, by using a Protocol as a concrete type specifier, etc. could benefit from this mechanism.

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


(Zhao Xin) #3

As far as I know, dynamicType is something that doesn't work until the app
is running the specific code, which means your codes are no longer
protected by the compiler. That is what swift tries to keep you from. So I
believe this should not happen in swift at any time. You should use
dynamicType as little as possible. You should try generics instead of
dynamic type.

As you said, you'd better to cast it to a protocol instead of dynamicType.

zhaoxin

···

On Sat, Jan 9, 2016 at 12:55 PM, Félix Cloutier <swift-evolution@swift.org> wrote:

func magic(_ variable: Any) {
let foo = variable as dynamicType
// ???
}

magic("hello")
magic(42)

What would be the result of this? What benefit do I get from casting it to
its dynamic type?

Félix

Le 8 janv. 2016 à 23:40:46, Michael Henson via swift-evolution < > swift-evolution@swift.org> a écrit :

Currently, the language syntax only allows type identifiers in the
type-casting-operator productions:

" " surrounds a keyword

type-casting-operator -> "is" type
type-casting-operator -> "as" type
type-casting-operator -> "as" "?" type
type-casting-operator -> "as" "!" type

The type production doesn't allow for expressions which resolve to a type,
only explicit type references.

So, if you want to refer to the item *as* its dynamic type, there's no
direct way to do that unless you declare the name of the type in code:

class Example {}
var value: Any = Example()
var again = value as value.dynamicType
// doesn't work because value.dynamicType is an expression

It should be possible to upcast to dynamicType immediately with no chance
of failure. To that end, I suggest adding two productions:

type-casting-operator -> "is" "dynamicType"
type-casting-operator -> "as" "dynamicType"

Following along the example above, we could then do:

var nowPossible = value as dynamicType

and have nowPossible be Example.Type.

Possible use cases for this functionality include:

1. Dealing with mixed-type collections from Objective-C code:
   @[ @"key1", @5, @"key2", @20, @"key3", @[@"red",@"green",@"blue"]]

2. Taking advantage of type-specific polymorphism without having to modify
code:

    func handleObject(obj: NSNumber) { print("Number") }
    func handleObject(obj: NSData) { print("Data") }

    func dispatchToHandler(kind: AnyObject) {
        print("dispatching \(kind.dynamicType)")
        handleObject(kind as dynamicType)
    }

I suspect that handling this use case might pose the most difficulties
when implementing the feature. It might make the whole thing impossible if
there's no way to resolve types at run-time in compiled code. For example,
if the dispatcher is in a Framework distributed as a binary and the user
does

class MyClass {}
func handleObject(obj: MyClass) { print "Success!" }

let stuff = MyClass()
dispatchToHandler(stuff)

in the project's code, what would happen?

Casting to an intermediate type between the static and dynamic types would
fall out naturally, though in that case you'd already have to know the
dynamicType and write the explicit intermediate type name in the code. If
that much is known then it's possible to cast directly to that intermediate
type with existing syntax.

Also, it's worth noting that the "Any" case is only the broadest instance
possible. Anything that passes data along as a super type, by using a
Protocol as a concrete type specifier, etc. could benefit from this
mechanism.

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

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

--

Owen Zhao


(Michael Henson) #4

Right, yes. That makes sense. It's clear to me now that this would require
adding the ability to dynamically dispatch / resolve method calls at
runtime, which is both a huge architectural change and probably
incompatible with Swift's design philosophy, even if the mechanism was
well-designed.

The use case that motivated the original idea is still valid, though. This
is a problem that is nearly trivial to solve in more dynamic languages, as
witnessed in the Objective-C compatibility example, but takes many lines of
code and much care to solve properly in Swift.

Mike

···

On Sat, Jan 9, 2016 at 6:35 AM, 肇鑫 <owenzx@gmail.com> wrote:

As far as I know, dynamicType is something that doesn't work until the app
is running the specific code, which means your codes are no longer
protected by the compiler. That is what swift tries to keep you from. So I
believe this should not happen in swift at any time. You should use
dynamicType as little as possible. You should try generics instead of
dynamic type.

As you said, you'd better to cast it to a protocol instead of dynamicType.

zhaoxin

On Sat, Jan 9, 2016 at 12:55 PM, Félix Cloutier <swift-evolution@swift.org > > wrote:

func magic(_ variable: Any) {
let foo = variable as dynamicType
// ???
}

magic("hello")
magic(42)

What would be the result of this? What benefit do I get from casting it
to its dynamic type?

Félix

Le 8 janv. 2016 à 23:40:46, Michael Henson via swift-evolution < >> swift-evolution@swift.org> a écrit :

Currently, the language syntax only allows type identifiers in the
type-casting-operator productions:

" " surrounds a keyword

type-casting-operator -> "is" type
type-casting-operator -> "as" type
type-casting-operator -> "as" "?" type
type-casting-operator -> "as" "!" type

The type production doesn't allow for expressions which resolve to a
type, only explicit type references.

So, if you want to refer to the item *as* its dynamic type, there's no
direct way to do that unless you declare the name of the type in code:

class Example {}
var value: Any = Example()
var again = value as value.dynamicType
// doesn't work because value.dynamicType is an expression

It should be possible to upcast to dynamicType immediately with no chance
of failure. To that end, I suggest adding two productions:

type-casting-operator -> "is" "dynamicType"
type-casting-operator -> "as" "dynamicType"

Following along the example above, we could then do:

var nowPossible = value as dynamicType

and have nowPossible be Example.Type.

Possible use cases for this functionality include:

1. Dealing with mixed-type collections from Objective-C code:
   @[ @"key1", @5, @"key2", @20, @"key3", @[@"red",@"green",@"blue"]]

2. Taking advantage of type-specific polymorphism without having to
modify code:

    func handleObject(obj: NSNumber) { print("Number") }
    func handleObject(obj: NSData) { print("Data") }

    func dispatchToHandler(kind: AnyObject) {
        print("dispatching \(kind.dynamicType)")
        handleObject(kind as dynamicType)
    }

I suspect that handling this use case might pose the most difficulties
when implementing the feature. It might make the whole thing impossible if
there's no way to resolve types at run-time in compiled code. For example,
if the dispatcher is in a Framework distributed as a binary and the user
does

class MyClass {}
func handleObject(obj: MyClass) { print "Success!" }

let stuff = MyClass()
dispatchToHandler(stuff)

in the project's code, what would happen?

Casting to an intermediate type between the static and dynamic types
would fall out naturally, though in that case you'd already have to know
the dynamicType and write the explicit intermediate type name in the code.
If that much is known then it's possible to cast directly to that
intermediate type with existing syntax.

Also, it's worth noting that the "Any" case is only the broadest instance
possible. Anything that passes data along as a super type, by using a
Protocol as a concrete type specifier, etc. could benefit from this
mechanism.

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

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

--

Owen Zhao


(Félix Cloutier) #5

You may be thinking of something like C#'s `dynamic` type. The C# compiler defers all checks, method resolution and overload resolution at runtime when a `dynamic` object is encountered.

I haven't used it a lot and I don't think that Swift would benefit a lot from it. However, it makes it easier to pick the "best" overload based on the runtime type: if you have Foo methods for 10-15 types, you can do Foo((dynamic)obj) to pick the appropriate one without a type switch.

Félix

···

Le 9 janv. 2016 à 14:21:50, Michael Henson via swift-evolution <swift-evolution@swift.org> a écrit :

Right, yes. That makes sense. It's clear to me now that this would require adding the ability to dynamically dispatch / resolve method calls at runtime, which is both a huge architectural change and probably incompatible with Swift's design philosophy, even if the mechanism was well-designed.

The use case that motivated the original idea is still valid, though. This is a problem that is nearly trivial to solve in more dynamic languages, as witnessed in the Objective-C compatibility example, but takes many lines of code and much care to solve properly in Swift.

Mike

On Sat, Jan 9, 2016 at 6:35 AM, 肇鑫 <owenzx@gmail.com <mailto:owenzx@gmail.com>> wrote:
As far as I know, dynamicType is something that doesn't work until the app is running the specific code, which means your codes are no longer protected by the compiler. That is what swift tries to keep you from. So I believe this should not happen in swift at any time. You should use dynamicType as little as possible. You should try generics instead of dynamic type.

As you said, you'd better to cast it to a protocol instead of dynamicType.

zhaoxin

On Sat, Jan 9, 2016 at 12:55 PM, Félix Cloutier <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

func magic(_ variable: Any) {
  let foo = variable as dynamicType
  // ???
}

magic("hello")
magic(42)

What would be the result of this? What benefit do I get from casting it to its dynamic type?

Félix

Le 8 janv. 2016 à 23:40:46, Michael Henson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Currently, the language syntax only allows type identifiers in the type-casting-operator productions:

" " surrounds a keyword

type-casting-operator -> "is" type
type-casting-operator -> "as" type
type-casting-operator -> "as" "?" type
type-casting-operator -> "as" "!" type

The type production doesn't allow for expressions which resolve to a type, only explicit type references.

So, if you want to refer to the item *as* its dynamic type, there's no direct way to do that unless you declare the name of the type in code:

class Example {}
var value: Any = Example()
var again = value as value.dynamicType
// doesn't work because value.dynamicType is an expression

It should be possible to upcast to dynamicType immediately with no chance of failure. To that end, I suggest adding two productions:

type-casting-operator -> "is" "dynamicType"
type-casting-operator -> "as" "dynamicType"

Following along the example above, we could then do:

var nowPossible = value as dynamicType

and have nowPossible be Example.Type.

Possible use cases for this functionality include:

1. Dealing with mixed-type collections from Objective-C code:
   @[ @"key1", @5, @"key2", @20, @"key3", @[@"red",@"green",@"blue"]]

2. Taking advantage of type-specific polymorphism without having to modify code:

    func handleObject(obj: NSNumber) { print("Number") }
    func handleObject(obj: NSData) { print("Data") }

    func dispatchToHandler(kind: AnyObject) {
        print("dispatching \(kind.dynamicType)")
        handleObject(kind as dynamicType)
    }

I suspect that handling this use case might pose the most difficulties when implementing the feature. It might make the whole thing impossible if there's no way to resolve types at run-time in compiled code. For example, if the dispatcher is in a Framework distributed as a binary and the user does

class MyClass {}
func handleObject(obj: MyClass) { print "Success!" }

let stuff = MyClass()
dispatchToHandler(stuff)

in the project's code, what would happen?

Casting to an intermediate type between the static and dynamic types would fall out naturally, though in that case you'd already have to know the dynamicType and write the explicit intermediate type name in the code. If that much is known then it's possible to cast directly to that intermediate type with existing syntax.

Also, it's worth noting that the "Any" case is only the broadest instance possible. Anything that passes data along as a super type, by using a Protocol as a concrete type specifier, etc. could benefit from this mechanism.

Mike
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution