Fork me on GitHub
#cljs-dev
<
2018-02-20
>
mfikes13:02:44

^ Sorted; just needed to call inc! on the async done latch

favila18:02:42

I want a reader literal which expands to cljs code that needs some imports to work. Is this possible without manually requiring the necessary imports in every ns the literal is used in?

dnolen18:02:55

I don’t think possible, also seems questionable :)

favila19:02:27

why questionable? It's not a problem in clj because the ns that implements the data reader does the require; it's only a problem because of the tiered compilation

dnolen19:02:18

I guess I just don’t know why you want to do that, data literals that require anything more than the reader tag fn just seems like a bad idea

favila19:02:32

Isn't that how spyscope works?

favila19:02:41

at least the spy/t stuff

favila19:02:57

in my case, I would like uuid to be transit uuids instead of clj-uuids

favila19:02:14

but to do that requires emitting code that depends on transit.types

dnolen19:02:10

I don’t use spy, but I dunno. I wouldn’t do this. Perhaps for ClojureScript it’s better for UUID to be overrideable since there’s no standard JS thing for that unlike Java

favila19:02:26

Tag as a shorthand literal for creating a type would be impossible; but if it's not a standard type you can live with macros

favila19:02:01

but it is something the clj people do, at least for defrecords

favila19:02:22

I don't have an answer though

dnolen19:02:30

hrm, I think I need to rewind a bit here

dnolen19:02:57

does Clojure itself implicitly require the nses of the data reader fns?

favila19:02:48

because compile and runtime are same process, reader fn can return the type instance directly

favila19:02:09

in cljs, often you need to emit something that will be evaluated later; this is where the require problem comes in

dnolen19:02:36

so reader fns in Clojure require if not already loaded?

favila19:02:57

they require to get the fn, but the ns is not available at the moment of reading

favila19:02:18

so you could return a thing; but not return a form that depends on the ns

favila19:02:54

actually it looks like the form returned from a reader fn is expanded in the ns of the reader fn?

favila19:02:12

the pp alias at least needs to be expanded; but you do need to inject (require 'spyscope.core) into your repl to make sure puget.printer is available.

favila19:02:35

nm, pp expansion probably occurred with the backtick; no magic

favila19:02:36

so the same technique would probably work in cljs: make sure you inject the requires/imports your readers need at the top of your code before building

dnolen19:02:52

@favila where is the implicit require in that project?

favila19:02:14

there is none; you are expected to add it by hand

dnolen19:02:29

oh so it’s exactly the same as Clojure then - that’s what I thought

favila19:02:10

there's just a class of problems that doesn't arise in clojure because the reader can return an instance

favila19:02:17

but it works the same

dnolen20:02:33

@favila ah maybe you’re not aware about how it’s supposed to work

dnolen20:02:44

data_readers.cljc can be loaded in both places

dnolen20:02:09

you cannot return instances, but you return whatever you want from the Clojure side to be interpreted as ClojureScript

dnolen20:02:20

so you can return what you need to construct the thing you want

favila20:02:10

yes I know

dnolen20:02:39

so then I don’t understand the problem, you just can’t return instances, but that’s not an issue for the record use case for example

dnolen20:02:46

I don’t see how what you want is different from that

favila20:02:08

but the emitted clojurescript still needs a require; this happens much less often in clj because it can just return the instance

favila20:02:10

that's all

dnolen20:02:30

it can only return the instance if the ns was already required though

dnolen20:02:41

I don’t see how this is any different

favila20:02:51

the data reader ns can do the require

favila20:02:14

e.g. uuid, or JSValue

dnolen20:02:15

but someone still has to require that

dnolen20:02:33

so I don’t really understand what you’re talking about

favila20:02:04

e.g. data_readers.clj contains {foo myfoons/foo-reader}

dnolen20:02:37

someone has to require something

favila20:02:44

myfoons.clj contains (ns myfoons (:require bar)) (defn foo-reader [x] (bar/make-bar x))

favila20:02:09

in this case the type is constructed at read time; bar is required by clojure loading myfoons to invoke the data reader fn

dnolen20:02:32

yes this is what I was saying

dnolen20:02:48

Clojure loads the data reader fn

dnolen20:02:02

way back above in the backlog

dnolen20:02:19

all this other stuff is moving around this fundamental point

favila20:02:16

yes, but clj can use that loading to make the type and return it directly; cljs needs an additional runtime load most of the time because the type cannot be constructed in clj

favila20:02:45

All I'm saying is it doesn't come up as much because clj can just make things that cljs would have to emit code to make later

favila20:02:02

and if you emit code to make later, you often need to require something

favila20:02:34

in both clj and cljs you have to inject the require somewhere at the top of your codebase so this works

dnolen20:02:42

let’s make sure we’re not talking past each other

dnolen20:02:51

1) Clojure has to load

dnolen20:02:57

full stop, nothing else is important

dnolen20:02:10

2) ClojureScript can’t runtime load

dnolen20:02:13

… but semantically the runtime load isn’t even important

dnolen20:02:02

you just want to know it will be present so it will work - one possible solution - we could make data reader nses implicit and higher in the dep chain

favila20:02:04

so you're talking about a solution to 2?

dnolen20:02:22

I’m just suggesting, this seems solveable - you just want to preserve a semantic

dnolen20:02:31

the details of how it works in Clojure don’t seem important to me

favila20:02:11

so proposal is: require nses mentioned by data_reader.cljc and data_reader.cljs in the cljs compilation stage of non-self-host

favila20:02:29

so that their requires are available to any code they emitted during the clj stage

dnolen20:02:12

yes and probably won’t even be a problem for libs to do this because of Closure DCE

favila20:02:33

that would be neat; it would make reader literals much more useful in cljs

dnolen20:02:01

patch is welcome, this doesn’t seems too tricky to do

dnolen20:02:16

just need to collect data readers first

favila20:02:21

we can't do any of this in self-host though

dnolen20:02:39

self-host is should be considered separately anyhow

favila20:02:55

and this is addressing a problem that doesn't really happen in self-host

dnolen21:02:28

so I would suggest fixing this in the build pipeline i.e. cljs.closure, no need to change anything else

dnolen21:02:13

@favila even if you don’t feel like taking it on feel free to submit an enhancement ticket with the proposed solution

favila21:02:22

working on it now

favila21:02:28

yeah, not sure I could take it on

john21:02:18

on the subject of requiring at runtime, how do you plan on handling this resolve-fn case for the prepl port? https://github.com/clojure/clojure/blob/86a158d0e0718f5c93f9f2bb71e26bc794e7d58e/src/clj/clojure/core/server.clj#L252

dnolen23:02:51

@john pREPL has nothing to do with writing ClojureScript

dnolen23:02:08

REPLs are written in Clojure

dnolen23:02:47

so no problem here 🙂