I have no idea what, if anything, Clojure the language(s) *should* do
about this issue, but I can explain the reasoning behind CLJX.

CLJX uses the reader to statically analyze toplevel forms in a file
and generate new ones according to declarative rewrite rules.
The motivating use case was to make the C2 data visualization library
work on both Clojure and ClojureScript.

C2's source is spit across

src/cljx ;;most of the code
src/clj  ;;Clojure-specific
src/cljs ;;ClojureScript-specific (i.e., DOM manipulation code)

and most of the cljx files only have one or two platform metadata
annotations.
Any namespace which uses macros has two ns forms to accomidate
ClojureScript's :use-macros syntax.

I explicitly wanted a solution where code for different platforms
would be in the same file because it eases the burden on the
maintainer to ensure consistency between implementations.
That makes sense when the differing implementations are very small:

(defn ^:clj log10 [x] (Math/log10 x))
(defn ^:cljs log10 [x] (/ (.log js/Math x)
                          (.-LN10 js/Math)))

and I agree with Dave in that it could get unwieldy fast if you try to
mix larger implementation-specific functions together.

If I wanted to write something cross-platform, I'd start by defining
the needed foundation (beyond what is provided by the Clojure
runtimes, e.g., "str"), write those platform-specific functions
completely separate from each other, and then write the shared Clojure
code that implements the bulk of the functionality.
The CLJX solution works nicely with C2 because 90% of C2 code
manipulates Clojure data structures only.
There are relatively few implementation details that need to be
papered over.

Clojure was designed to be a hosted language, and it's very easy to
reach out to the underlying platform.
If you don't need to do that and can get by with Clojure/core---great,
your code will be portable.
However, if you use libraries and facilites native to the host
platform, then you're not writing Clojure so much as you are writing
Clojure+Java or Clojure+JavaScript.
If that's the case, just have separate projects with a shared spec or
test suite and not worry about mashing it all together with compiler
or pre-processing tricks.

On Apr 13, 10:06 am, Aaron <aaroncrael...@gmail.com> wrote:
> I posed this question briefly in this post here:  
> https://groups.google.com/d/msg/clojure/K65Va0rCCls/Ow5bAJ_YTGIJ.  In this
> real world example of porting Korma over to ClojureCLR, I encountered the
> following things:
>
>    - One namespace which handled JDBC interaction needed to be rewritten
>    completely to target ADO.NET
>    - Another namespace required a few minor changes, only one of these
>    (changing .indexOf to IndexOf) was platform specific
>
> Korma is a library that is probably exceptional in its avoidance of
> platform specific features in most namespaces.  Porting something like
> swank would not have been so easy.  In general, I would say that for this
> library, I would prefer to use the platform specific folder approach - i.e
> having two namespaces korma.platform.db and korma.platform.util in src-jvm/
> and src-clr/ folders.  Then there could be a CLR specific project.clj
> (maybe project.clr.clj) sitting next to the JVM project.clj (and eventually
> maybe a project.py.clj).  Each project.clj would reference the correct
> platform specific folder in addition to the shared src/ folder.  Just off
> the top of my head, the reasons for supporting this approach are:
>
>    - It forces the developer to isolate platform specific code into
>    manageable units that can be 1) more easily ported to another platform, 2)
>    easily maintained, and 3) tested in isolation for compatibility
>    - There is no need for one clojure dialect to know about the whereabouts
>    or contents of code for another dialect.  This would seem to be unnecessary
>    overhead.
>
> While I can see why it might be nice to be able to quickly add some
> metadata to distinguish this platform specific code while keeping
> everything in one file, as other have mentioned, I would encourage people
> to think about the downsides of this.  Say, I had just taking korma.db and
> put some conditionally compiled CLR code alongside the JVM code.  The file
> doubles in size.  Would I then want the py team to do the same?  Also, for
> the one .indexOf -> IndexOf change, say there are little changes like that
> all over the place.  Would a team adding a new port want to go through the
> whole source tree and find every instance of this?  Without modifying the
> clojure compilers we have now, the platform specific directory approach
> will work and is probably cleaner.  It just requires team consensus on
> adopting this approach.
>
> One thing, I would propose is adding some build tool awareness of this so
> that maybe an NLein or PyLein could use the same project.clj and just see
> :platform-clr, :platform-py, :platform-jvm attributes.  Or this could be
> done by having a shared project.shared.clj included by each platform
> specific project file.  These types of approaches might be simpler and more
> maintainable in the long run.
>
> Aaron
>
>
>
>
>
>
>
> On Thursday, April 12, 2012 12:56:59 PM UTC-4, tbc++ wrote:
>
> > I've been thinking lately how to seamlessly merge clojure-py and
> > clojure-jvm code in the same packages. This is something I know has
> > been discussed in the past, but I'm just looking for
> > ideas/brainstorming on how we can solve this problem.
>
> > Let's begin by explaining the problem. Let's assume that my project
> > needs a platform specific way to convert a int to a string:
>
> > On clojure-jvm:
>
> > (defn to-string [i] (.toString Integer i))
>
> > On clojure-py:
>
> > (defn to-string [i] (py/str i))
>
> > On Clojurescript:
>
> > (defn to-string [i] (.toString i))
>
> > We could do this inline (inside a common .clj file):
>
> > (for-platform "jvm"
> >                   (defn to-string [i] (.toString Integer i))
> >                   "python"
> >                   (defn to-string [i] (py/str i))
> >                   "js"
> >                   (defn to-string [i] (.toString i)))
>
> > But this gets ugly real fast.
>
> > My idea, would be to provide some sort of hook to the compiler, that
> > would be cross-platform. The compiler, when looking for a namespace,
> > would find all files in a given folder that match the required
> > namespace:
>
> > /test/to_string.clj
> > /test/to_string.cljpy
> > /test/to_string.cljs
> > /test/to_string.cljclr
>
> > These function hooks would then pick the best entry based on the
> > extension, defaulting to .clj if no better option exists. Since these
> > functions could be composable it would be possible to also dispatch on
> > platform versions:
>
> > /test/to_string.cljpy26       ; Python 2.6 code
> > /test/to_string.clj7            ; JVM 7 code
>
> > It seems to me that this would be a very clean way to allow clojure
> > programs to be cross-platform. The side-effect is that it would force
> > non-standard code out into separate namespaces where they can be
> > easily maintained. If someone wanted to port the project to a new
> > platform, he would need only to find existing platform overrides, and
> > create new entries.
>
> > Thoughts?
>
> > Timothy Baldridge

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to