Skip to content

Adding dynamic properties on top of the Mirror-values for context variables / Improved support for computed properties #339

@ralfebert

Description

@ralfebert

I just digged into the topic of how to use computed properties with Stencil because I had this issue in a project of mine.

This was already discussed here:

This bug report was closed because this feature was added:

I was looking for something better compared to the workaround "don't use computed properties, always set regular properties instead". For example, if you want to pass a struct to Stencil like this and use the sum property:

struct Prices {
    
    let prices: [Decimal]
    
    var sum: Decimal {
        prices.reduce(0, +)
    }
    
}

you could use something like this:

struct Prices {
    
    let prices: [Decimal]
    
    var sum: Decimal = 0
    
    mutating func updateSum() {
        self.sum = prices.reduce(0, +)
    }
    
}

I didn't like this solution too much, thus this bug report. The only clean alternative would be manually mapping the data types to Dictionary, which would mean a lot of manual busywork for complex types.

I tinkered with DynamicMemberLookup, you could add the sum property yourself, but then you loose the support for accessing other properties via the Mirror approach. One could copy the Mirror#getValue method from Stencil and use that as fallback, but looking at that method and the nil-handling I thought: no, better not.

I wondered:

Would it make sense to fall back to the Mirror-resolving if DynamicMemberLookup doesn't resolve a value? That way one could add code to add computed properties by manually resolving them.

So you could add something like this:

extension Prices: DynamicMemberLookup {
    subscript(dynamicMember member: String) -> Any? {
        if member == "sum" {
            return self.sum
        }
        return nil
    }
}

and could still access the prices property without manually resolving it.

This currently is not possible, if it implements DynamicMemberLookup, it will not resolve via Mirror anymore:

https://github.com/stencilproject/Stencil/blob/4f222ac85d673f35df29962fc4c36ccfdaf9da5b/Sources/Stencil/Variable.swift#L121:L124

Or maybe an extra protocol like DynamicMemberLookup that allows to add dynamic properties on top of the mirrored ones like that?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions