Error formatting macro: pagetree: java.lang.NullPointerException

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The APIs of many core and contrib libraries were designed with particular platforms in mind. For example, the clojure.string library specifically does NOT duplicate core functionality already found in the java.lang.String API, such as ‘contains’ and ‘substring’. Another example are basic math operations like ‘sqrt’ and ‘log’.  

 This means that idiomatic JVM Clojure code, of necessity, makes extensive use of interop forms for basic features. This means in turn, that almost all code intended for multiple platforms will encounter one of Problems 1-3.

Proposals

Simple macro

Put feature data in a global dynamic var.

Write a simple macro (called, for example, 'feature-cond') which has test and value expressions. The test expressions could check the feature data (perhaps with some syntactic sugar or pattern matching), and the value expressions would be emitted only if the feature expression passed.

Example:

(defn sqrt [x]

  (feature-cond

    :js (Math/sqrt x)

    :jvm (java.lang.Math/sqrt x)

    :clr (System.Math/Sqrt x)))

Benefits:

  • No modification to the core language
  • No conceptual leaps

Tradeoffs:

  • Would break if used inside existing macros that rewrite or inspect their source, since they would see the 'feature-cond' expression rather than the evaluated platform-specific expression.
Rewriting macro

Put feature data in a global dynamic var.

Allow users to edit a (possibly global) substitution mapping, possibly with syntactic sugar or pattern matching.

Wrap forms which may contain platform-specific code in a macro which will introspect the code and replace specified symbols with alternative symbols from the substitution map.

Example:

(def-alternative builtins/sqrt

:js Math/sqrt

:jvm java.lang.Math/sqrt

:clr System.Math/Sqrt)
(replacing-alternatives

(defn sqrt [x]

(builtins/sqrt x)))

Benefits:

  • No modification to the core language
  • No conceptual leaps

Tradeoffs:


Feature expressions

Read-time eval

New macro phase

Compiler reads metadata for interning forms

Source rewriting

Considerations

Granularity

At what level does the solution allow users to target code? Currently, one could say that code can bet targeted at the "classpath" level; multiple versions of the same code can't be on the same classpath during compilation. This implies that code targeting different platforms must be in different files which either reside in different directories or have different file extensions.

...

Many of the proposals involve testing what features are available/present.  

Flexibility

Locality

Locality

Proposals

This implies that there is a data structure, global or ambient at compilation time, that is inspect-able to determine what the environment is.

What kind of a data is present, how detailed it is, and what the actual structure of the representation is is largely orthogonal to which proposal is selected.

Power

What is possible when detecting a platform/feature? In order of least to most powerful:

  • Simple boolean check
  • Composite boolean checks (and & not operators allowed)
  • Range checks (greater than, less than, equality checks)
  • Arbitrary code execution

Locality

To what degree does the proposal preserve referential transparency? Is it always possible to tell if/when some code might be modified just from looking at that code, or could some other code be modifying it "from a distance"?

Compatibility

Is there any possible way the proposal could cause problems when used with existing code?

Programmatic Visibility

Using the proposal, is it possible to reflect/introspect on the parsed value to see where it came from and verify that it was the result of a feature expression? See Kevin Downey's comment: http://dev.clojure.org/display/design/Feature+Expressions?focusedCommentId=5243068#comment-5243068