SE-0195 — Introduce User-defined "Dynamic Member Lookup" Types

This feature replaces the use of string subscripts, which have this same problem.

The problem with automatic wrapper generation, which has been stated before, is that some dynamic languages don’t declare all their properties upfront. How would you work around this issue?

That said, I think there is an argument to be made for generating a static interface from what information is available (my uninformed impression is that type providers allow this), and providing a subscript fallback.

In any case, this proposal seems to be designed to make writing wrapper classes easier. If you don’t use wrapper classes, you’ll get no static guarantees with or without this proposal.

Likewise it can be quite frustrating to be pointed at the proposal as soon as a concern or an idea for mitigation of such concerns comes up when the proposal does not address them.

In this example the idea of making dynamic call sites more visible is only discussed in general in the proposal. The specific suggestion made by @hlovatt and others, to mark expressions with dynamic or dyn, which is relatively lightweight, is not discussed at all in the proposal.

Instead the proposal chooses an unnecessary heavyweight method of marking the use sites as an example which is misleading IMHO.
Let me explain why I think that the method chosen as an example in the proposal is unnecessarily heavyweight:

  • the chosen ^ sigil for the example is visually intrusive, especially when combined with . (because ^ is a sigil in the upper region of a glyph whereas . is in the lower region, so they don’t combine well visually)
  • the sigil is not only applied to the name lookup but in addition to the call itself which is unnecessary for the concern raised most often: that the dynamic name lookup might fail due to a typo or broken refactoring. It is not a concern that the call itself might fail (I expect here that the dynamic name lookup for a method respects the parameter list for the method, i.e. looking up foo(1, 2) would fail if only a method foo(PyVal x) would exist, but not a method foo(PyVal x, PyVal y)).

Choosing another sigil for dynamic name lookup, i.e. -> and not applying it to the call itself would then result in the following example which is much more readable. For operators let’s choose a prefix ' (all sigil suggestions are only straw men, of course):

let np = Python.import("numpy")
let x = np->array([6, 7, 8])
let y = np->arange(24)->reshape(2, 3, 4)

let a = np->ones(3, dtype: np->int32)
let b = np->linspace(0, pi, 3)
let c = a '+ b
let d = np->exp(c)

The suggestion of using something similar to try would look like follows (and is missing from the discussion in the proposal although it has been mentioned several times):

let np = Python.import("numpy")
let x = dyn np.array([6, 7, 8])
let y = dyn np.arange(24).reshape(2, 3, 4)

let a = dyn np.ones(3, dtype: np.int32)
let b = dyn np.linspace(0, pi, 3)
let c = dyn a+b
let d = dyn np.exp(c)

The advantage of this approach is that there is no separate sigil necessary for operators. The proposal states

Requiring additional syntax for a.b but not a + b (which can be just as dynamic) would be inconsistent.

This clearly ignores the fact that marking expressions with dyn (similar to try) would solve this inconsistency.

Furthermore the whole discussion of whether or not to make call sites more visible is not representing the concerns raised on Swift Evolution well, so let me restate the concern:

  • Static type checking ensures that member access or method calls cannot fail due to the member or method not being present on the receiver, i.e. static type checking protects from typos and errors made when renaming things. For dynamic member lookup this is not true anymore and it is not visible where dynamic lookup is used.

IOUs are somewhat of an exception to this rule although even there the member accesses or method calls are checked statically and only fail when the IOU is nil (and in that case all would fail).

The discussion in the proposal rightly notes that

Swift’s type system already includes features (optionals, IUOs, runtime failure) for handling failability.


Adding punctuation to the lookup itself reduces the likelihood that an API author would make the lookups return strong optionals, because of increased syntactic noise.

This might be true but

  1. something like dyn would not visually conflict with the ? introduced by strong optionals.
  2. I do not consider it good design to conflate the failure of member lookup (remember: due to a typo, i.e. a programming error) with a return value being optional because of application logic, i.e. the failures have a different nature.

A similar point raised against marking the use sites of dynamic member lookup is that Swift already contains features that might fail at runtime like array subscripts, integer overflow or IOUs.

IMHO this, too, ignores the fact that these runtime failures have a different nature than failures when looking up a member: the existing features do never fail because of a misspelled name. Of course their failures are programming errors, too, and they might even be the result of typos (e.g. using + instead of -) but inherently they are errors in the program logic (which are generally difficult to detect automatically) whereas lookup failures due to misspelled names can be found quite easily automatically by static type checking.

This failure due to typos is why I do not agree with the claim of type safety made by the proposal. IMHO it is only dynamically type safe but not statically type safe.


This feature replaces the use of string subscripts, which have this same problem.

The potential issue is quite clear when a string literal is used as a subscript.

If you don’t use wrapper classes, you’ll get no static guarantees with or without this proposal.

Of course you will never get the same kind of guarantees that you do with static dispatch. For example, the underlying Python type could change a member name.

However, if you declare constants for the members in use you can get a guarantee that all uses of that member are using the same string value. In other words, you avoid duplicating string literals throughout your code. There is value in doing this whether you are writing a wrapper or not. For example, if the underlying Python type did change a member name you only need to update a single constant to bring your Swift code back in sync with Python.

1 Like

If used strictly for writing wrapper classes, there would only be a single duplication in the case of settable properties, and even then it would be localised. Everything else should be a single-line callthrough to the dynamic method/property.

I would consider extended use of this feature outside of writing wrappers an abuse of this feature, and am concerned that this feature makes that far too easy.

I’m not sure I follow, see above.

I agree. This shouldn’t be an issue, but only if the feature isn’t abused. I’m not sure whether to give the proposal the benefit of the doubt in this regard.

An alternative to the dynamic {} syntax suggested, is only allowing dynamic accesses/calls within types marked @wrapper. This would have the benefit of hinting to the user the correct usage.

It depends. If you’re just wrapping the type directly that is true. But I can imagine cases where the wrapper would be a lightweight facade that may use the same member of the underlying Python type in a few different places.

If the only purpose of this feature is to sugar code within direct wrappers of dynamic types I would be strongly opposed to it. Providing sugar for that limited context is not at all worth introducing a feature with such a broad scope.

I’m pretty sure the intent is that the feature will be used more liberally. There are a variety of contexts where that tradeoff might make sense (such as ad-hoc scripts and newcomers from other languages). That is why I am not opposed to the feature, I just want to see it designed in a way that reduces the potential harm to large teams comprised of developers of mixed skill levels.


Thought of one other thing the proposal does not account for: can dynamic members satisfy protocol requirements? I’d be inclined to say “no”, mostly because I have no idea how it would work with types and also because that seems like magic that’s likely to get someone into trouble. But maybe someone else has thought about it more. (It’d also be a compatible change to go from “no” to “under certain circumstances” in the future, since dynamic member lookup only kicks in after regular lookup fails.)


The Core Team met on Wednesday, January 31 to discuss the proposal and the feedback from the review. There’s been a lot of great discussion, and the review thread unsurprisingly bifurcates on two important subtopics:

  1. Is this the right direction for Swift, and if so, is this the right general approach?

  2. Assuming the direction and approach is more-or-less correct, discussion about specific details (e.g., should the approach use a marker protocol).

After reviewing the discussion in this review thread and discussing this review within the Core Team, the Core Team has decided the answer to #1 is “yes”. The proposal is accepted in principle, but specific details of the proposal need to be further discussed and ironed out. Specifically, there is the matter of using a marker protocol, which raises a bunch of technical questions.

On the general principle of the proposal, the Core Team felt that:

  • This proposal added valuable functionality to Swift
  • This proposal is not at odds at potentially adding any new dynamic affordances to Swift later that (say) tie into Swift’s runtime metadata, etc.
  • There are tooling affordances, such as syntax coloring, that can be used to distinguish methods call going through this member lookup mechanism — without adding additional syntactic weight that would be at odds of some of the core goals of this proposal

@Chris_Lattner3 has a revised version of the proposal, which can be found here:

The previous version of the proposal can be found here:

The review will extend for another week to discuss the revised details of the proposal.

Thank you to everyone who has participated in the review. The insights and feedback has been invaluable. The review will continue on this review thread.


Thanks @tkremenek! The revised proposal is substantially the same as the previous revision of the proposal, the only change is to resyntax it from being a marker protocol:

   struct YourType : DynamicMemberLookupProtocol { ... 

into an attribute:

  struct YourType { ... }

The actual diff to the proposal is visible here if it helps. I wouldn’t be surprised if I missed updating something minor, if so, let me know and I’ll address it.



I don’t see any alternative like the following in the proposal, so I’m wondering if it had been considered we could just make it an attribute on the subscript itself?

struct PyVal {
  subscript(pythonMember name: String) -> PyVal {

It looks cleaner to me since the attribute is kept close to the member it refers to. Also, the name of the subscript parameter no longer needs to be follow a hard-coded value.

If the DynamicCallable proposal too is going to switch to an attribute form too, maybe the attribute sould be attached to the relevant member function too.

A brief reply on the revisions to the proposal—

I agree with the conclusion that the original marker protocol didn’t enable useful generic algorithms and that being able to use it as an existential doesn’t seem to offer much benefit.

But I would think that this observation is a good argument for adopting the alternative associated type design that Chris originally outlined. It would enable the spelling of an explicit protocol requirement. And, conceivably, a protocol that refines DynamicMemberLookupProtocol could then provide useful extension methods.

I rather think that such a state of affairs would be superior to the current one, where no such refinements are possible. Moreover, the aesthetics of @dynamicMemberLookup @dynamicCallable public struct PyVal is vastly inferior; it’s simultaneously less readable and more in-your-face, IMO.

1 Like

My review of the new proposal is brief: I don’t see strong advantage or disadvantage to either the marker protocol or the attribute. Both are fine. None of the pros and cons discussed seem particularly strong to me. I defer entirely to those who have opinions on the matter.

Thanks to Chris, Ted, and core team for patiently shepherding this forward.

1 Like

My original opinion still stands. I think this proposal is a good improvement for Swift. My only input for this small change is that @dynamicMemberLookup, while visually less appealing than a protocol, serves a better purpose.

The way the previous proposal was given, the marking protocol had no actual requirements defined inside. So the @dynamicMemberLookup does give some visual indication that this new functionality has some intrinsic stuff built into the compiler.

What’s more, I believe this will possibly help alleviate some people’s concerns that this functionality will spread to become a thorn in Swift projects. From my experience in the Swift community, even an additional @ or # is enough to give the novice or uninformed enough caution that they will go and lookup what the usage of this attribute is, and what it’s meant for, rather than blindly slapping it on because it makes something “easier”.

tl;dr: I’m fine with this change and am still +1

  1. Can protocols use this attribute? I am assuming no but wanted to confirm.

  2. Do subclasses inherit the attribute?

  3. Can it be mixed with @objc classes?

  4. Can nested types use the attribute?

1 Like

I don’t have a super strong opinion about this, but my weak preference is to put this on the type. Rationale: this affects the global behavior of the type, meaning that we want the attribute to be easily visible as part of the type declaration (not buried under hundreds of lines of other members and methods). The subscript is an implementation detail of the behavior, but the behavior itself is the key thing to model.

Also, by requiring it on the type, it makes it immediately obvious that you cannot add this in an extension.



Yes, Yes, Yes, Yes.


1 Like

Hi Xiaodi,

The attribute still works with existentials. You can define something like:

protocol MyThing {
  func randomRequirement()

  subscript(dynamicMember: String) -> Self? { get set }

… and all types that conform to MyThing will get the dynamic behavior, and have their requirement spelled according to the protocol requirement - all without needing an explicit associatedtypes (which make existentials complicated). This sort of example was mentioned by Joe Groff, and is what really made me realize that this is better as an attribute that protocols can use, rather than be a protocol itself.

It is quite possible I’m misunderstanding you. If so, I apologize, please restate and I’ll try again :-)

On aesthetics, the general style is to put attributes on the preceding line, I don’t think this is unwieldy, but I can see how others would feel differently. In any case, actual use of the attribute is not going to be super common, so the concrete syntax is less important than getting the language model right (imo).

@dynamicMemberLookup @dynamicCallable 
public struct PyVal {



I bit of a bikeshed, considering aesthetics:

how about :

@dynamic(memberLookup, callable)
public struct PyVal {

Works for me, I don’t have a strong preference either way. This might conflate these with the ‘dynamic’ declmodifier in some people’s minds, but I don’t think that would be a significant concern.

What do other people think?


1 Like

That’s certainly more visually appealing than having multiple @ attributes. As for conflating with the dynamic modifier, it’s been my experience that this modifier is not very common, so I’m not that worried about that.

My only worry is people would get confused as to what the difference between dynamic and @dynamic(...) are, and why they’re separate.

Terms of Service

Privacy Policy

Cookie Policy