Yes. With #sourceRoot
too, all the use cases I can think of would still be possible. I like that idea much better than the status quo.
Without derailing from the main topic, with all these new keywords being pitched I think the context is growing too fast. Would it make sense to generalize that into a special StaticContext<T>
type where the generic parameter allows the users to specify the subset of all #keywords
, so that the context value isn't exploding in size where not appropriate? This will also reduce the number of parameters a function must have to obtain such static context compared to current status quo.
There was a similar topic, but instead of smashing everything inside one type it would be far better if we could specify a subset of static information we want to obtain:
I agree, that would be a good idea, especially since people are in fact relying on the current behavior of #file
and we don't want to disrupt them, so that suggests to me introducing new context values would be preferable to breaking the existing ones.
I really like the idea of StaticContext
. It's much more usable than an ad-hoc collection of parameters that all have to be forwarded individually.
Aside the pitch from @davedelong, I tried to create my own type to accumulate the context but I failed because the current static capturing behavior isn't that trivial as I initially thought.
So it definitely requires a formal proposal and some compiler help to create such a type.
Now that __FILE_NAME__
exists in clang for C family languages, it seems like a no brainer to add #fileName
for Swift -- same behavior available for all languages.
Which "size" are you concerned about, in particular? The memory of a Context
object, or the "mental" size of a large Context API with many properties?
At least in the former case, we should implement #context
in such a way that values can be emitted as static global data.
That's what I would have thought.
It would be an issue if all properties were stored, for all uses of #context, even if only a properties are every accessed.
Could there be an optimization to only populate that data which will actually be referenced? Though I imagine an optimization like that would be defeated as soon as someone passes a Context
object across a module boundary, or dumps/prints the entire object.
It would be easy to make it so that if you did something like func foo(x: String = #context.file)
, we only instantiate the file
string. Passing around whole context values might be trickier, though in most cases they would probably be passed around as read-only, so if the type is large enough that we pass it indirectly we would just pass the global pointer around.
It would be pretty cool to have a really cheap context like this, especially if it could support Hashable
by just comparing / hashing the pointer value.
If it's acceptable to say that context values are only ever compiler-generated, then the type representation could be a plain pointer to the global compiler-generated value. That might cut off possibilities for manipulating context values when forwarding them through different logging APIs, though.
Could that be mitigated by making Context
be a reference type? Then compiler generates references would be a pointer to the static information, but as a developer Iβd still be able to lash up my own composite/altered contexts.
I'd very much love to be able to carry around source location information as some form of thing "together" very cheaply -- a pointer to a static, compiler generated, immutable "location context" would be quite great. We currently pass around #file and #line, though sometimes I think to myself "function might have been nice to carry here as well" but we don't since it's too much hassle at some point (debate-able, maybe worth it to carry around, maybe not).
Usage patterns we have for these things are usually:
- carry around the location info always
- very rarely actually access it -- only when things went wrong, then in asynchronous programs one can say "the thing that originated at line ... failed"
- this isn't a replacement for full on tracing, but a simpler lightweight source location focused helper
Introducing anything reference type for this hurts the first point, as it'd have to be refcounted I guess; and I can't really afford risking those refcounts in hot code paths (where the carrying is used).
So an immutable compiler generated + direct pointer to it sounds quite great to me -- carrying it around would be cheap, just a pointer after all, and no refcount since the source location info is "immortal" <3
I think this is acceptable for source location; more advanced things I'd expect to go full on tracing (open tracing / dapper / pivot tracing style), and those are runtime generated and kind of expected to "weight" a bit.
Don't value types that are bigger than a certain threshold (~40 bytes I think but not declared as it's implementation detail) behave like that under the hood?
I'm sure we could get around that. If there was something like a SourceContext
type in the standard library (which only the compiler could construct), the compiler could also know that those objects are always singletons/immortal and omit reference counting.
True my bad actually about the worry about the reference types for this. As long as we know itβs immortal itβs fine indeed.