Readwrite reflection in Swift

(forwarding a discussion on Swift reflection from swift-users)

It seems there is no disagreement on how reflection is something we would
want in Swift. Given that until this is part of the language, it will be a
blocker for several types of projects - both mocking frameworks, and data
modeling runtime (as Jens Alfke mentioned) - I would be keen to understand
the constraints swift wants to have in place so we can put a proposal
together.

Specifically:
- Regarding interfaces, is there any direction or proposal on the
interfaces to be used for reflection, or is this up for discussion?
- Regarding security, what model would the goal be? Would something like
the .NET security model (classes declaring security critical attribute
cannot be accessed using readwrire reflection be suffcient? Details on
this: Security Considerations for Reflection - .NET Framework | Microsoft Learn ). To my knowledge .NET has the most tight
reflection rules in place, all other popular typed languages (e.g. Java,
Ruby) are all more relaxed.
- Would secrecy also be a language goal on top of security - e.g. the
ability to disallow even read reflection for certain members?

- Gergely

···

---------- Forwarded message ----------
From: Joe Groff <jgroff@apple.com>
Date: 17 December 2015 at 22:07
Subject: Re: [swift-users] Reason for Swift not having readwrite reflection
To: Gergely Orosz <gergely.orosz@gmail.com>
Cc: swift-users@swift.org

On Dec 17, 2015, at 10:54 AM, Gergely Orosz via swift-users < swift-users@swift.org> wrote:

As a user of swift, building projects on top of it, the single biggest
limitation I've come across is that *all *my unit tests are significantly
more bloated compared to Objective C... because mocking & stubbing is not
possible due to the static nature of the language and that readwrite
reflection is not supported.

I did some research and apart from C++ and C I couldn't find any other
popular language that does not support readwrite reflection (here's a post
I wrote on the topic: Swift: The Only Modern Language without Mocking Frameworks - The Pragmatic Engineer ).

Not having readwrite reflection makes it impossible to create any mocking
frameworks for unit testing, which is a very common tool in the testing
world. Without this we're left with using dummies and fakes - for now
creating them manually, in the future I'm sure there will be plugins that
support generating these from e.g. protocols.

The iOS community seems to be somewhat behind when it comes to automation
compared to other languages and platforms - and in its current version
Swift seems to make the barrier to entry even higher compared to Objective
C, where mocking and stubbing is a possibility due to the dynamic nature of
the language.

Could anyone shed some light on why the decision was made to leave this
feature out? Is it just a feature that due to complexity will be pushed for
later? Or is it a security consideration?

Yes, yes, and yes. Better reflection is something we'd like to support
eventually, and a lot of the necessary metadata is already present at
runtime, but not exposed. Designing interfaces takes time, and there are
also security and secrecy concerns regarding what ought to be reflected, so
there needs to be language design as well to control what is available to
runtime reflection. All that said, runtime reflection is not the only way
to approach mocking and stubbing. Swift's as static as you write it; if you
define your component interfaces using protocols and generics, those
protocols can be conformed to with mock or stub implementations without any
need for runtime hacking.

-Joe

(forwarding a discussion on Swift reflection from swift-users)

It seems there is no disagreement on how reflection is something we would want in Swift. Given that until this is part of the language, it will be a blocker for several types of projects - both mocking frameworks, and data modeling runtime (as Jens Alfke mentioned) - I would be keen to understand the constraints swift wants to have in place so we can put a proposal together.

Specifically:
- Regarding interfaces, is there any direction or proposal on the interfaces to be used for reflection, or is this up for discussion?

It is up for discussion.

- Regarding security, what model would the goal be? Would something like the .NET security model (classes declaring security critical attribute cannot be accessed using readwrire reflection be suffcient? Details on this: Security Considerations for Reflection - .NET Framework | Microsoft Learn ). To my knowledge .NET has the most tight reflection rules in place, all other popular typed languages (e.g. Java, Ruby) are all more relaxed.

The reflection system will not allow write capabilities by default. You will *definitely* have to opt in to that with something like dynamic.

- Would secrecy also be a language goal on top of security - e.g. the ability to disallow even read reflection for certain members?

It is very likely that most kinds of reflection will be opt-in — if nothing else, we are very concerned about the binary-size hit of including runtime descriptions of every declaration in the program.

John.

···

On Dec 17, 2015, at 11:21 PM, Gergely Orosz via swift-evolution <swift-evolution@swift.org> wrote:

- Gergely

---------- Forwarded message ----------
From: Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>>
Date: 17 December 2015 at 22:07
Subject: Re: [swift-users] Reason for Swift not having readwrite reflection
To: Gergely Orosz <gergely.orosz@gmail.com <mailto:gergely.orosz@gmail.com>>
Cc: swift-users@swift.org <mailto:swift-users@swift.org>

On Dec 17, 2015, at 10:54 AM, Gergely Orosz via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

As a user of swift, building projects on top of it, the single biggest limitation I've come across is that all my unit tests are significantly more bloated compared to Objective C... because mocking & stubbing is not possible due to the static nature of the language and that readwrite reflection is not supported.

I did some research and apart from C++ and C I couldn't find any other popular language that does not support readwrite reflection (here's a post I wrote on the topic: Swift: The Only Modern Language without Mocking Frameworks - The Pragmatic Engineer ).

Not having readwrite reflection makes it impossible to create any mocking frameworks for unit testing, which is a very common tool in the testing world. Without this we're left with using dummies and fakes - for now creating them manually, in the future I'm sure there will be plugins that support generating these from e.g. protocols.

The iOS community seems to be somewhat behind when it comes to automation compared to other languages and platforms - and in its current version Swift seems to make the barrier to entry even higher compared to Objective C, where mocking and stubbing is a possibility due to the dynamic nature of the language.

Could anyone shed some light on why the decision was made to leave this feature out? Is it just a feature that due to complexity will be pushed for later? Or is it a security consideration?

Yes, yes, and yes. Better reflection is something we'd like to support eventually, and a lot of the necessary metadata is already present at runtime, but not exposed. Designing interfaces takes time, and there are also security and secrecy concerns regarding what ought to be reflected, so there needs to be language design as well to control what is available to runtime reflection. All that said, runtime reflection is not the only way to approach mocking and stubbing. Swift's as static as you write it; if you define your component interfaces using protocols and generics, those protocols can be conformed to with mock or stub implementations without any need for runtime hacking.

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

Also consider alternatives to the use cases you described—mocking and data modeling can also be accomplished by compile-time code generation, and by features like type providers that supply external type information to the compiler. Runtime reflection is definitely useful in many cases, but compile-time approaches are likely to be easier to verify and maintain, faster, and more secure.

-Joe

···

On Dec 17, 2015, at 11:21 PM, Gergely Orosz via swift-evolution <swift-evolution@swift.org> wrote:

(forwarding a discussion on Swift reflection from swift-users)

It seems there is no disagreement on how reflection is something we would want in Swift. Given that until this is part of the language, it will be a blocker for several types of projects - both mocking frameworks, and data modeling runtime (as Jens Alfke mentioned) - I would be keen to understand the constraints swift wants to have in place so we can put a proposal together.

Specifically:
- Regarding interfaces, is there any direction or proposal on the interfaces to be used for reflection, or is this up for discussion?
- Regarding security, what model would the goal be? Would something like the .NET security model (classes declaring security critical attribute cannot be accessed using readwrire reflection be suffcient? Details on this: Security Considerations for Reflection - .NET Framework | Microsoft Learn ). To my knowledge .NET has the most tight reflection rules in place, all other popular typed languages (e.g. Java, Ruby) are all more relaxed.
- Would secrecy also be a language goal on top of security - e.g. the ability to disallow even read reflection for certain members?

I'm very interested in reflection in Swift. As Joe says, designing
interfaces takes time, but since one of the goals of Swift 3 is to
stabilize the ABI, and since the ABI might affect the ability to perform
reflection operations, or at least their performance, it's important to
work this out sooner rather than later. If there's any help I can provide
in that regard, I'm happy to provide it.

I do have a question about precisely what you mean by "readwrite
reflection". I assume you mean adding/removing/swizzling
properties/functions at runtime, but it's possible you mean get property
values by name, but don't set property values by name. I definitely want to
set property values by name. I would like to be able to, for example, write
an implementation of decodeObjectOfClass:forKey which walks a class or
struct's public properties and sets them automatically.

I don't have any need for .NET-style reflection security, but it doesn't
negatively impact me either.

···

On Thu, Dec 17, 2015 at 11:21 PM, Gergely Orosz via swift-evolution < swift-evolution@swift.org> wrote:

(forwarding a discussion on Swift reflection from swift-users)

It seems there is no disagreement on how reflection is something we would
want in Swift. Given that until this is part of the language, it will be a
blocker for several types of projects - both mocking frameworks, and data
modeling runtime (as Jens Alfke mentioned) - I would be keen to understand
the constraints swift wants to have in place so we can put a proposal
together.

Specifically:
- Regarding interfaces, is there any direction or proposal on the
interfaces to be used for reflection, or is this up for discussion?
- Regarding security, what model would the goal be? Would something like
the .NET security model (classes declaring security critical attribute
cannot be accessed using readwrire reflection be suffcient? Details on
this: Security Considerations for Reflection - .NET Framework | Microsoft Learn ). To my knowledge .NET has the most tight
reflection rules in place, all other popular typed languages (e.g. Java,
Ruby) are all more relaxed.
- Would secrecy also be a language goal on top of security - e.g. the
ability to disallow even read reflection for certain members?

- Gergely

---------- Forwarded message ----------
From: Joe Groff <jgroff@apple.com>
Date: 17 December 2015 at 22:07
Subject: Re: [swift-users] Reason for Swift not having readwrite reflection
To: Gergely Orosz <gergely.orosz@gmail.com>
Cc: swift-users@swift.org

On Dec 17, 2015, at 10:54 AM, Gergely Orosz via swift-users < > swift-users@swift.org> wrote:

As a user of swift, building projects on top of it, the single biggest
limitation I've come across is that *all *my unit tests are significantly
more bloated compared to Objective C... because mocking & stubbing is not
possible due to the static nature of the language and that readwrite
reflection is not supported.

I did some research and apart from C++ and C I couldn't find any other
popular language that does not support readwrite reflection (here's a post
I wrote on the topic: Swift: The Only Modern Language without Mocking Frameworks - The Pragmatic Engineer ).

Not having readwrite reflection makes it impossible to create any mocking
frameworks for unit testing, which is a very common tool in the testing
world. Without this we're left with using dummies and fakes - for now
creating them manually, in the future I'm sure there will be plugins that
support generating these from e.g. protocols.

The iOS community seems to be somewhat behind when it comes to automation
compared to other languages and platforms - and in its current version
Swift seems to make the barrier to entry even higher compared to Objective
C, where mocking and stubbing is a possibility due to the dynamic nature of
the language.

Could anyone shed some light on why the decision was made to leave this
feature out? Is it just a feature that due to complexity will be pushed for
later? Or is it a security consideration?

Yes, yes, and yes. Better reflection is something we'd like to support
eventually, and a lot of the necessary metadata is already present at
runtime, but not exposed. Designing interfaces takes time, and there are
also security and secrecy concerns regarding what ought to be reflected, so
there needs to be language design as well to control what is available to
runtime reflection. All that said, runtime reflection is not the only way
to approach mocking and stubbing. Swift's as static as you write it; if you
define your component interfaces using protocols and generics, those
protocols can be conformed to with mock or stub implementations without any
need for runtime hacking.

-Joe

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

Also consider alternatives to the use cases you described—mocking and data
modeling can also be accomplished by compile-time code generation, and by
features like type providers that supply external type information to the
compiler. Runtime reflection is definitely useful in many cases, but
compile-time approaches are likely to be easier to verify and maintain,
faster, and more secure.

-Joe

I am aware of the current alternative of specifying dependencies to be

mocked complile time. However I see a major issue on how protocols need to
be added that are only used by the test code - yet they ship as part of the
production code.

For example consider a method that opens an external URL from the
application by invoking the UIApplication.sharedApplication().openUrl(...)
method. In order to write a unit test to verify this call is being made a
new protocol needs to be specified that defines the openUrl() method, as
UIApplication does not implement any protocols (lets call this
UIApplicationProtocol). Then via an extension UIApplication needs to
inherit this UIApplicationProtocol, and the original code can be changed to
use a UIApplicationProtocol dependency when invoking openUrl().

My main issue is that UIApplicatipnProtocol is not used anywhere in the
production code, but purely added to enable testing. The same applies for
any developer specified class - to enable testing often a matching protocol
needs to be specified, even if this protocol is not needed or used by the
production code.

If in order to be able to unit test production code, that code needs to
ship with test-only code, then I do feel that indicates that the language
is not very "test friendly". In Objective C one can write production code
as simple as intended and by replacing methods runtime do all the testing
they want in their test project. Of course there is a performance hit -
however the vision of Swift is to get all the benefits of Objective C
without having to worry about performance

Being able to opt in to reflection would be a good start - this would give
developers an option to choose whether or not to sacrifice any performance
for the sake of a bit cleaner code (no test-only protocols).

Howeve opt-in reflection will still not solve how to unit test calls to
foundation classes like in my example - will the recommendation be for
developers to specify their own extension protocols for these foundation
class methods they want to test? Or would it make sense for all foundation
classes to also implement a protocol to give more support for this kind of
unit testing?

Also for test code performance is much less of an issue - would it be
feasible to apply different restrictions to reflection for test projects?
In a similar way to how the @testable declaration sidesteps some of the
security limitations of non-public members, could @testable also be used to
relax reflection restrictions for the imported code?

Thanks,

Gergely

I think this is something really valuable in multiple cases and I'm
particularly interested in having this to improve the usage of inversion of
control. However, I wonder if this is possible due the strong static typing
from Swift or if it may not reduce the safety of the language.

But I found the current limitations regarding this matter very educational
actually, because enforces us to really design our code using interfaces
instead of concrete implementations which aligns with one of the SOLID
principles, Dependency inversion.

In your example for example, by adopting this principles we should not rely
in the instance of UIApplication directly but instead define an interface
that represents this intention of opening an URL like you have suggested.
But I think this is valuable not only because it makes the code testable
but specially because we can achieve an abstraction of UIApplication class
itself making it reusable. Suppose that you want to reuse this code in
another architecture, e.g. Linux, having this abstraction you will not need
to adapt your code but instead only provide a concrete implementation for
your current target, Linux, iOS or even unit-tests.

- David

···

2015-12-18 22:09 GMT+00:00 Gergely Orosz via swift-evolution < swift-evolution@swift.org>:

Also consider alternatives to the use cases you described—mocking and data

modeling can also be accomplished by compile-time code generation, and by
features like type providers that supply external type information to the
compiler. Runtime reflection is definitely useful in many cases, but
compile-time approaches are likely to be easier to verify and maintain,
faster, and more secure.

-Joe

I am aware of the current alternative of specifying dependencies to be

mocked complile time. However I see a major issue on how protocols need to
be added that are only used by the test code - yet they ship as part of the
production code.

For example consider a method that opens an external URL from the
application by invoking the UIApplication.sharedApplication().openUrl(...)
method. In order to write a unit test to verify this call is being made a
new protocol needs to be specified that defines the openUrl() method, as
UIApplication does not implement any protocols (lets call this
UIApplicationProtocol). Then via an extension UIApplication needs to
inherit this UIApplicationProtocol, and the original code can be changed to
use a UIApplicationProtocol dependency when invoking openUrl().

My main issue is that UIApplicatipnProtocol is not used anywhere in the
production code, but purely added to enable testing. The same applies for
any developer specified class - to enable testing often a matching protocol
needs to be specified, even if this protocol is not needed or used by the
production code.

If in order to be able to unit test production code, that code needs to
ship with test-only code, then I do feel that indicates that the language
is not very "test friendly". In Objective C one can write production code
as simple as intended and by replacing methods runtime do all the testing
they want in their test project. Of course there is a performance hit -
however the vision of Swift is to get all the benefits of Objective C
without having to worry about performance

Being able to opt in to reflection would be a good start - this would give
developers an option to choose whether or not to sacrifice any performance
for the sake of a bit cleaner code (no test-only protocols).

Howeve opt-in reflection will still not solve how to unit test calls to
foundation classes like in my example - will the recommendation be for
developers to specify their own extension protocols for these foundation
class methods they want to test? Or would it make sense for all foundation
classes to also implement a protocol to give more support for this kind of
unit testing?

Also for test code performance is much less of an issue - would it be
feasible to apply different restrictions to reflection for test projects?
In a similar way to how the @testable declaration sidesteps some of the
security limitations of non-public members, could @testable also be used to
relax reflection restrictions for the imported code?

Thanks,

Gergely

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

Do you plan any changes to allow write reflection?

My main use case for this feature, like many users I'm sure, would be to allow mocking types at runtime, instead of having to rely on generators (like mockingbird) or manually written mock classes with unnecessary protocols for every concrete class in the source code.

I understand the security concerns and to me a compromise could be simple: allow opting in to read-write reflection on test/debug builds only. This keeps the door shut for attacks at runtime, yet allow for a much better developer experience at devtime

What do you think?

1 Like