Fork me on GitHub
#clojurescript
<
2019-08-14
>
andy.fingerhut00:08:48

Does JS and/or ClojureScript provide a way to restrict oneself to exact integer arithmetic, i.e. wrapping or exceptions are OK, but auto-promoting to floating point numbers is not?

dnolen00:08:33

ClojureScript is just JS arithmetic - so semantically doubles

dnolen00:08:27

VM of course attempt to do integer arithmetic for performance and we rely on that - but there's no way to do anything that wouldn't damage perf

andy.fingerhut00:08:36

So even all the JS stuff like (num | 0) doesn't prevent arithmetic ops from promoting to floats?

dnolen00:08:53

that just clamps to int

dnolen00:08:18

but semantically N.N... to N.0

andy.fingerhut00:08:33

I think AppleSoft BASIC was the last language I used that did that. Maybe Perl, I guess.

andy.fingerhut00:08:50

People that implement bignum arithmetic libs in JS are just really careful with their arithmetic expressions I guess?

dnolen00:08:14

you have to implement your own arithmetic

dnolen00:08:23

foo.add etc.

dnolen00:08:21

could have probably done things that way in the beginning but probably would have needed to do a lot of stuff to recover perf

dnolen00:08:23

but time has shown it to be a very low value add for most users - JavaScript thus ClojureScript aren't used much for numerics

andy.fingerhut00:08:04

makes sense. Just trying to familiarize myself with the differences. Thx for the quick info.

dnolen01:08:50

It's a fundamental JS issue - so if / when it gets sorted out there - we'll probably follow along

alpox10:08:55

I asked this here before but I'm going to ask again in hope to get some more input: Does anyone have experience with embedded databases in ClojureScript (Electron)? I'm trying to figure out what I'd best use for a small amount of entities with few relations but possibly a lot of datapoints/rows for each entity. I want the data to be persistent on the users computer and don't want that the user needs to install additional tools (ex. MongoDB). My current contestants I found are: LevelDB (Through LevelUp), Sqlite3 (embedded) and NeDB (embedded MongoDB-like DB). Any experience report / suggestions / inputs are welcome 🙂

Roman Liutikov10:08:28

There’s IndexedDB backed by SQLite, built into Chrome so you can use that without installing additional modules

alpox10:08:32

If you talk about WebSQL (Not sure), I heard it is deprecated/discontinued

alpox11:08:39

And with IndexedDB alone I fear that full-text searches would become a bit tricky

Roman Liutikov11:08:29

indexeddb yes, I’m not aware of existing implementations of full text search for it unfortunately

alpox11:08:40

Ah this looks interesting. Thanks for the read! I guess I may also consider to use Dexie.js directly as it implements certain features out of the box.

Ahmed Hassan11:08:16

There's https://pouchdb.com/ I haven't used it but it may help.

alpox12:08:02

@UCMNZLJ93 that looks actually very useful and there seem to be text search extensions for it. It might also allow to make support for datasync accross devices easy.

👍 4
Ahmed Hassan12:08:55

What I'm curious about is how can we sync it with PostgreSQL backend.

Ahmed Hassan12:08:37

And if we can't, wouldn't it be better to use Dexie.js.

alpox12:08:45

I dont really think it makes a difference in that case. With both, Dixie and Pouchdb we would have to program the sync ourselves and transport from key/value stores to Postgres or any SQL db. Unless I miss some aspect.

Ahmed Hassan12:08:22

Dexie is lighter than Pouchdb, but in the end it depends on requirements and features. Pouchdb probably have more features.

alpox13:08:40

Maybe yes. But I also think that Pouchdb might have better community support than Dexie. I just now remembered that the Meteor.js framework uses a Browser integrated Database too. https://www.npmjs.com/package/minimongo might be worth a glimpse.

👍 4
Ahmed Hassan18:08:33

Lovefield is developed using Closure Library: https://github.com/google/lovefield

alpox18:08:57

@UCMNZLJ93 thanks! It looks very interesting and seems to have quite some traction looking at the github stars. Ill dig into it a bit

Ahmed Hassan18:08:33

This seems probably best option to me, I'll be glad to listen feedback on it from you.

Roman Liutikov19:08:39

AFAIK Lovefield is used in GMail

Roman Liutikov19:08:38

you can confirm this by searching for lovefield in sources with gmail open

alpox20:08:45

I think I'll give lovefield a shot! I might first have to write a small wrapper though 🙂 not sure how long it takes me to get going given my adept status in CLJ 😄

alpox14:08:02

I did give lovefield a shot and also began writing a (very small) wrapper for it but I soon noticed some things: • While I found about all things I needed, the documentation is still quite confusing • Lovefield assumes only one connection at a time to the database which is fine for my kind of app but often falls short in the web environment (PouchDB has concurrency support integrated): >Lovefield assumes that at a given time, there is only one connection to a database instance. By design the tuple (origin, schema name, version) uniquely identify a database instance on data store. If there are multiple pages or tabs connected to the same database, there can be a problem of data inconsistency. Users shall be aware of this problem and plan accordingly. • Lovefield has no sync protocols (except Firebase) like PouchDB. • Lovefield has no support for attachments - This can maybe be worked around in a wrapper - PouchDB would have this integrated though. • Lovefield builds typed tables upon the untyped indexeddb and works extensively with versions/upgrades (Or shall I say migrations) and brings relational SQL-like convenience to the Web-World. This is nice for when its needed - I noticed that this is overkill for me and makes it harder to deal with my data where a No-SQL design fits perfectly well. • Lovefield needs a connection created asynchronously to be able to access the database where PouchDB gives us an instant db object to work with. Latter makes it simpler to use as we do not have an initial time in which no requests are allowed. I believe a simple workaround to this would be to use a promise-chan async channel in place of the db object of lovefield and access the channels value in a query-wrapper before making the requests - i'm not so sure if thats a good idea though. These are some points which popped up for me until now - not sure if there will be any more as I lean towards giving PouchDB a shot due to the points listed I could work around most of the shortcomings of LoveField I see - but I don't believe its worth my time for now

alpox10:08:01

I should maybe add that I'd like to implement text-search features at some point which might make a difference

dominicm13:08:41

how can I start a repl-env such that I can run (cljs.repl/-evaluate repl-env "<NO_SOURCE_FILE>" 1 "console.log('hi');")?

andy.fingerhut20:08:57

You want to evaluate that as a Clojure/Java expression?

andy.fingerhut20:08:13

Because in my quick tries in a Node-based REPL evaluating ClojureScript expressions, there is no cljs.repl/-evaluate defined at all.

andy.fingerhut20:08:55

With a deps.edn file that contains only this line: {:deps {org.clojure/clojurescript {:mvn/version "1.10.520"}}} I can run clj command from terminal, get a Clojure/Java REPL user=> prompt, and at least (require 'cljs.repl) followed by (doc cljs.repl/-evaluate), and it exists. I do not know what arg to pass for repl-env to do something useful with that.

dominicm07:08:29

It's a clojure function, yeah.

ivana13:08:12

Hello! Can I get js array element by index in more js-y way, than (-> arr js->clj first)? Js arrays have not get or at magic methods, but I dont know how to use [] in cljs interop 🙂

Roman Liutikov13:08:58

in fact you can use nth

Roman Liutikov13:08:10

(nth #js [1 2] 1)

Roman Liutikov13:08:26

as well as first

ivana13:08:31

oh, just directly with js objects?

Roman Liutikov13:08:43

JS Array to be precise

ivana13:08:38

magic! :male_mage:

thheller13:08:04

if you know you are working with js array it is better to use aget directly

thheller13:08:34

nth always needs to check the coll it is working with first

8
neupsh21:08:56

How can i force the execution order of these three things in clojurescript world? The second one is blocking (right now testing with js/timeout for some ms):

:on-click (fn []
                          (reset! updating? true)
                          (edit-complete-handler-fn @updated-value)
                          (reset! updating? false))

neupsh21:08:46

the first and third run immediately, even before second is completed

dpsutton21:08:23

what does edit-complete-handler-fn look like?

neupsh21:08:02

@dpsutton right now:

(fn [] (timeout (reset! edit-mode? false) 3000))
but it will have a real implementation later

neupsh21:08:48

timeout is just (js/setTimeout f ms) ..

neupsh21:08:57

.... and looks like i found the bug

neupsh21:08:19

the reset function is supposed to be a lambda :face_with_rolling_eyes:

dpsutton21:08:24

that you're calling reset! immediately. yup 🙂

neupsh21:08:29

hmm, that fixed the dialogbox immediately closing, but updating? ratom is not changing the actual button to "disabled"

neupsh21:08:45

I think those three expressions are still executed in async

dpsutton21:08:14

Why schedule resetting it to false if you immediately swap it back to false?

neupsh21:08:04

they are different ones. edit-mode is local to parent component, setting it true opens up dialog, the`on-click` handler is in "update" button of dialog. I wanted to disable the button while it is updating, so updating? is component local for the dialog (not the parent component). What needs to be done for "updating" is handled by the parent, thus edit-complete-handler-fn is a callback to parent with the updated value

neupsh21:08:03

I guess I could just skip setting udpating? to false as well since the dialog is going to go away once the value is updated

dpsutton21:08:06

(reset! updating? true) ;; disables button
(edit-complete-handler-fn @updated-value)
(reset! updating? false) ;; reenables button?
is this true?

dpsutton21:08:09

then that's so quick you shouldn't really see the button as disabled

neupsh21:08:55

yes, but edit-complete-handler-fn takes 2 seconds to complete (js/timeout), it should have disabled it and then in 2 seconds enable it but it is async so both get fired before the actual handler function is completed. For now I think i can skip the last expression altogether.

dpsutton21:08:13

it completes immediately

dpsutton21:08:18

it schedules something to run in 2 seconds

👏 4
neupsh21:08:31

aah.. that is where I misunderstood

👍 4
neupsh21:08:24

how can i make that function to take 2 seconds? sort of like (Thread/sleep 2000) in java/clojure ?

dpsutton21:08:47

that doesn't exist in js

neupsh21:08:18

How do you simulate long running process in clojurescript/js ?

dpsutton21:08:30

promises, core.async, callbacks. there are several tools

👍 4
alpox22:08:00

@neupsh

on-click (fn []
                          (reset! updating? true)
                          (js/setTimeout (fn [] (reset! updating? false)) 2000))
Callbacks should work and all the other things mentioned

Lu09:08:53

@neupsh exactly this .. you have to call your second reset fn in the callback of your middle event that is supposed to take some time .. remember that js is single threaded and non blocking .. which means it’ll never wait for anything 😊🙌:skin-tone-3:

neupsh13:08:01

I was doing this before, but I needed it only for test. I wanted to put the delay in the function that I was calling not on the caller

neupsh13:08:27

But looks like this is the only way to do it

alpox13:08:57

@neupsh You can still put the delay in the other function - but you'd have to pass a callback over to it with what you want to do after:

(defn some-other-func [cb]
  (js/setTimeout 
    (fn []
      (do-something-after-time-elapse)
      (cb)) ;; The callback is called here
    2000))

;; .....

(reset! updating? true)
(some-other-func #((reset! updating? false))) ;; Pass the callback

neupsh13:08:14

@U6JS7B99S yes, that is what I was trying to avoid 🙂

dijonkitchen23:08:10

Anyone know why Clojure keeps 0.0 as 0.0, but CLJS changes it to 0?

mfikes23:08:20

In ClojureScript, numbers that happen to be integers are rendered as such. (ClojureScript uses the one JavaScript numeric type.)

dijonkitchen23:08:38

Thanks, seems tricky when sending doubles from server only to have them come back as non-doubles that need to be coerced.

mfikes23:08:02

Well, what I'm saying is that, in ClojureScript, they are all effectively doubles even if they print like integers.

mfikes23:08:52

In, short, it is just a rendering concern.

dpsutton23:08:34

try 0.0 in a browser console and you'll observe the same behavior

mfikes23:08:46

Ahh, TIL

$ jsc
>>> 0.0
0
>>> 0.1
0.1

mfikes23:08:14

(Node and GraalJS behave similarly; perhaps this is specified? Cool.)

dpsutton23:08:17

I think that js just has “number” there aren’t integers at all. So js doesn’t (and cant) distinguish an integer zero from a float zero

mfikes23:08:11

Right. The specific thing I'm wondering about: Does JavaScript specify how numbers are rendered, thus causing the console and all of the JavaScript REPLs above to print zero as 0.

dpsutton23:08:13

I can’t imagine any way to do it without tagging all numbers with precision. How would it print 0.0, 0.00, etc

dpsutton23:08:34

But your question is about specification and not implementation right?

mfikes23:08:12

Yes, probably 7.1.12.1 step 2 which says > If m is +0 or -0, return the String "0".