You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
At first glance I thought Analytics.track(name:properties:) could take any Codable type in the properties dictionary since everything is eventually encoded to JSON, but after closer inspection I discovered that isn't the case sine you use a custom JSON enum that only handles a subset of what can be encoded to JSON.
Here is a place in our code where that assumption is visible:
// If the value is Codable then leave it as is and let Segment encode it into JSON, otherwise make use of CustomStringConvertible
letloggingValue:Any= value as?Codable?? value.description
analytics.track(name: segmentEvent, properties:["value": loggingValue])
Here I am checking if the value we want to log is Codable and if it is that gets sent as is, and if it isn't then get a string description to send instead. That way the value can be sent with as much information as possible when it is Codable.
Problem is this leads to a crash in DEBUG builds when value is Codable but isn't handled by the JSON enum (like Set).
Describe the solution you'd like
I don't know the history of why a JSON enum is used instead of Codable (or just Encodable) and JSONEncoder, but if it is possible to update Analytics.track(name:properties:) to use [String: Encodable] instead of [String: Any] and then use JSONEncoder to encode the dictionary I think that would be the simplest, and would provide the strongest compile time guarantees.
A change like that would be disruptive enough to warrant waiting 2.0, but I'd love to see it earlier, so perhaps the old can be kept and marked deprecated in 1.4 and then removed in 2.0.
Describe alternatives you've considered
If you can't use the standard JSONEncoder for some reason, then a custom protocol can be used instead of Encodable in place of Any and extend the supported types in JSON with that protocol. Something like SegmentSerializable.
The Encodable solution would be fit in with the Swift ecosystem, as it would allow us to send anything we want to Segment by making it Encodable, and give us compile time assurance that what we are sending will make it to Segment.
If that is deemed impossible for reasons I can't see from the outside I will accept the alternative where at the very least we get compile time assurances.
The text was updated successfully, but these errors were encountered:
Thanks @rtharston! I'll dive in and see what I can do. We use the JSON type as an intermediary because there's a lot to an event payload that is freeform and doesn't fit nicely into a Codable type.
I'm curious what you mean by 'freeform', and what you are adding to the payload that isn't Codable. Everything that is supported in the JSON enum in JSON.swift is a Codable type. (Arrays and Dictionaries are Codable if their contents are Codable.)
Of course I understand that asking to replace JSON with Codable is a big task and there are likely gotchas I don't know about because I haven't worked on this codebase, but from my limited, outside view it seems like it should be possible. 😁
@rtharston once we dive into plugins and whatnot, we don't really have any control of how or what people will modify, add or remove. Unstructured dictionaries break the codable paradigm and there's a lot of unstructured bits. I am having a look how I can tighten this up though.
@rtharston there's also a track<T: Codable>(... properties: T?) that might be useful to you, not sure. Lemme know what you think of this change. Seems to be just what you asked for at the call site.
Uh oh!
There was an error while loading. Please reload this page.
Is your feature request related to a problem? Please describe.
At first glance I thought
Analytics.track(name:properties:)
could take any Codable type in the properties dictionary since everything is eventually encoded to JSON, but after closer inspection I discovered that isn't the case sine you use a custom JSON enum that only handles a subset of what can be encoded to JSON.Here is a place in our code where that assumption is visible:
Here I am checking if the value we want to log is Codable and if it is that gets sent as is, and if it isn't then get a string description to send instead. That way the value can be sent with as much information as possible when it is Codable.
Problem is this leads to a crash in DEBUG builds when value is Codable but isn't handled by the JSON enum (like Set).
Describe the solution you'd like
I don't know the history of why a JSON enum is used instead of
Codable
(or justEncodable
) andJSONEncoder
, but if it is possible to updateAnalytics.track(name:properties:)
to use[String: Encodable]
instead of[String: Any]
and then useJSONEncoder
to encode the dictionary I think that would be the simplest, and would provide the strongest compile time guarantees.A change like that would be disruptive enough to warrant waiting 2.0, but I'd love to see it earlier, so perhaps the old can be kept and marked deprecated in 1.4 and then removed in 2.0.
Describe alternatives you've considered
If you can't use the standard
JSONEncoder
for some reason, then a custom protocol can be used instead ofEncodable
in place ofAny
and extend the supported types in JSON with that protocol. Something likeSegmentSerializable
.In JSON.swift:
Additional context
The Encodable solution would be fit in with the Swift ecosystem, as it would allow us to send anything we want to Segment by making it Encodable, and give us compile time assurance that what we are sending will make it to Segment.
If that is deemed impossible for reasons I can't see from the outside I will accept the alternative where at the very least we get compile time assurances.
The text was updated successfully, but these errors were encountered: