stencilproject/Stencil

Revisit behaviour of undefined values

ilyapuchka opened this issue · 6 comments

Current behavior of Variable.resolve when it encounters undefined values is IMO inconsistent with other kinds of errors, like an unknown filter, which results in an exception. Accessing undefined value, i.e. blog.uri instead of blog.url results in the empty output instead of exception or JavaScript-like output "undefined" which can be confusing for users.

Before #245 when resolving properties of collections unknown keys were simply skipped, resulting in contacts.something.0 render the same way as contacts.0 instead of raising an exception or returning nil. With #245 resolving arrays and string properties was refactored so it will now return nil. But the issue is still present for dictionaries.

Expected behavior:

  • accessing undefined property should result in an exception by default, we can add configuration to allow ignoring such errors and printing them out as a warning or completely ignoring them and render empty string, "nil" or anything else
  • rendering nil values can still result in an empty string or can be configured to render "undefined" or anything else per user choice, i.e. "nil"/"null"
  • resolving unknown properties on any collection type should behave the same way as resolving unknown properties of any other type
  • accessing collection elements out of bounds should result in exception by default but can be configurable to warn in console or completely ignore this and render empty string, "nil" or anything else
djbe commented

I'm in the "throw error if it doesn't exist" camp, but might be best to have this configurable.

An issue might be that sometimes, you don't know if a property exists or not, and we have no way of knowing if the object blog has a property url or not, so even if we decide one way or the other, we might want to add some mechanism so that template writers can test for this.

Jinja has a whole bunch of undefined types that can be configured, we might want to mirror some of that functionality (and obviously have a "decent" default setting):
http://jinja.pocoo.org/docs/2.10/api/#undefined-types

Yes, this should be configurable to some degree. Though what do you mean "don't know if a property exists or not"? We can add is defined check to test for that, i.e. when resolving dictionary keys (to check if key contains nil or is not present at all), but IMO as we are talking about Swift environment there shouldn't be such thing as "undefined" on any other type. Also should accessing out of bounds index in collection result in nil or exception? I'd say exception, but can be also configurable.

djbe commented

Nah I mean for example:

  • Stencil is configured to the "throw exceptions" mode
  • I write a template, but at some point, some property (or variable, ...) may or may not exist
  • As a template writer, before I trigger an exception, I'd like to test if the property/variable/... exists

By "may not exist" you mean "value of the property is nil at runtime" or "there is no such property on the type at all"?

In the first case, I think it should not through any exception by default and there should be a way to check for that at runtime, like != nil in Swift. But we can have a "strict" mode that will treat accessing any nil values as errors.

The second case should by default result in the exception, but this can be softened via configuration.

djbe commented

I think there may be multiple levels? And a != nil check is needed.

  • Accessing nil is okay, non-existing property is okay (returns nil)
  • Accessing nil is okay, non-existing property throws
  • Accessing nil throws, non-existing property throws

The same should actually apply to KVO, if we can't find property using recently introduced selector check - we should raise exception