Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zen modules dependency aliases #31

Open
KGOH opened this issue Aug 31, 2022 · 3 comments
Open

Zen modules dependency aliases #31

KGOH opened this issue Aug 31, 2022 · 3 comments

Comments

@KGOH
Copy link
Contributor

KGOH commented Aug 31, 2022

After #27 will be implemented there will be increasing chance of namespace collisions.

Problem example:

  • package1: defines namespaces A, B. A depends on B here
    A.edn
    {ns A
     import #{B}
     sym {:zen/tags #{B/tag}}}
  • package2 defines namespaces B and C. C depends on B here
    C.edn
    {ns A
     import #{B}
     sym {:zen/tags #{B/tag}}}
  • I'm interested in package1.A/sym namespace and in package2.C/sym
  • I import both packages as my dependency.
  • Namespaces collision by the name B will break one of these packages

Possible solutions:

  • suggest user to copy and patch names in the lib with name clash manually
  • add local custom package prefixes. When specifying a dependency could/should specify also a prefix which will prepend ALL of the symbols in this dependency

Urgency: low
This may be important architecture decision, i.e. we may want to decide to force all deps to have local alias

@KGOH
Copy link
Contributor Author

KGOH commented Aug 31, 2022

Naive prefix solution:

;; our package 1 specifies deps like this
[[steve "url1"]
 [johny.r "url2"]
 [stan "url3"]]

;; deps in the "url2" repo
[[stan.r "url1"]]


;; our package after dependency download
zen-modules/
    steve/
       some-ns.edn: {ns some-ns sym1 {}} ;; prefix all symbols with `steve on ns read 
    stan
       some-ns.edn: {ns some-ns sym3 {}} ;; prefix all symbols with `stan on ns read
    johny/
     r/
      some-ns.edn: {ns some-ns sym2 {} ;; prefix all symbols with `johny.r on ns read
                    import {stan.some-ns}}
      stan/
        some-ns.edn {ns some-ns sym1 {}}  ;; prefix all symbols with `johny.r.stan on ns read
zrc/
    main.edn: {ns main
               import #{steve.some-ns johny.r.some-ns}

               symbol
               {...
                steve.some-ns/rsym
                johny.r.some-ns/vsym}}

This specific soultion makes the same package occur multiple times, but this can be fixed by not so naive implementation, for example we can store package under a uid and maintain aliases to uid relation in a package-lock file, then substitute local alias during a namespace read in zen

@KGOH
Copy link
Contributor Author

KGOH commented Aug 31, 2022

We should do analysis why other systems like Clojure don't do prefixes. My guess is stat code is a dynamic entity and can not be definitely statically analyzed, but zen-lang is fully static and we can find & check all symbols used in a project which enables us to do prefixes like this

We also need to find what are the drawbacks of prefixes (I couldn't find any)

@KGOH
Copy link
Contributor Author

KGOH commented Sep 1, 2022

(require '[clojure.walk])


(defn prefix [x]
  (symbol (str "johny."
               (when-let [nsps (namespace x)]
                 (str nsps "/"))
               (name x))))


(-> '{ns foo
      import #{bar baz}
      sym {:zen/tags #{zen/schema}
           :type zen/map
           :foo bar/b
           :keys {:a {:type zen/string}}}}
    (->> (clojure.walk/postwalk
           (fn [x]
             (if (and (qualified-symbol? x)
                      (not (= "zen" (namespace x))))
               (prefix x)
               x))))
    (update 'ns prefix)
    (update 'import #(into #{} (map prefix) %)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant