Fork me on GitHub

Is there a way to have “private” functions in Sci? I found that when I’m writing Sci macros I’m forced to expose more functions than I want. Does this sound familiar?


Would be most clear with an example


i was affraid so 😅 I’ll try to compile something simple


btw, because of your comment I noticed that bb and sci don't care about private 😂

$ bb '(ns foo) (defn- foo []) (ns bar (:require foo)) (foo/foo)'


clojure doesn’t care to much about private vars either (#'some-private-var)


Below is a contrived example of a case where I use a macro. I want to expose view-of to the Sci environment. Ideally only this macro would be available but that doesn’t work. I need to expose view-of* as well or the macro generates code that the interpreter doesn’t understand. Now the view-of* function can also be called directly.

(defn view-of* [ctx label some-value]
  (internal-function-here some-value)

(def view-of
  (fn [_&form _&env & body]
    `(the-exposed-ns/view-of* (pr-str ~body) (do [email protected]))))


another confusing thing is that ` doesn’t work as expected. You need to know where the view-of is mapped to


Yeah, that's how macros work. Any code that they generate could also have been typed in by the user.


I’m not saying Sci should fix this. Just another level of complexity


Yeah I guess you are right


What I usually do here is end the function name with -impl to indicate that it's not something you should call directly.


yeah makes sense. In another case I’m using a specific namespace for the implementation


good to know i’m not crazy. Thanks 🙂

👍 1

> Logseq is using sci, they seem to be inspired by Roam @borkdude Yes, Roam is a huge inspiration for logseq, logseq will not be a outliner and the graph view without Roam! I'll just copy some text I replied to the Athens community yesterday here: User privacy is an essential thing for Logseq. We believe user's notes should be stored locally, the server will never store user's private notes, and we do provide publishing so that you can publish on Logseq, in the future, you can publish it to any platforms like Github pages or netlify. It can sync your notes using Git, Github is supported now, more options (Custom hosted Git service, Dropbox, WebDAV, etc.) are in the roadmap. Currently, logseq already have most features similar to Roam Research (huge inspiration) like outliner editor, block(and page) references and embeds, graph visualization, we also have directly hiccup support and a live Clojure Interpreter which is using You can also specify any datascript queries (to filter blocks, pages, tags or anything in the datascript db), you can also specify a custom view component for any queries (using hiccup). Another big difference between logseq and other tools (including Roam) is that logseq work directly with the plain text (markdown, org mode, etc.), if you're familiar with Obsidian, logseq is something like a web Obsidian with Roam's killer features like the outliner and block embeds. I've been using logseq for organizing my notes and todos for two months (it works on mobile too), but I think it's still early days, some users from the logseq discord group reported some bugs like file corrupts. So please don't use it for serious writings now. Logseq draws a lot of great ideas from Roam (outliner, backlinks, sidebar), Emacs org mode (heading properties, todo keywords, priorities), and Tiddlywiki (transclusions, contents, and lists), hats off to all of them!

👍 1
😯 1

(= int? (sci.core/eval-string "(comp (comp int?))"))
; => true


Is there a way to access :line and :column information outside of exception conditions?


I’m using sci to render reagent components and valid sci code is causing invalid reagent results. I would like to use the line and column information to provide feedback for the user. I’m not able to get it from the sci context AFAIK


If I could get access via a dynamic var like sci/*current-line* that would work for me. Does this make sense?


I guess a function would make more sense as it would not give overhead for cases where this is not being used


Maybe related to being able to control iteration / have a custom step function


line and column information is available as metadata on forms and symbols


I don’t think this would allow to do something like the below, right?

`(sci/eval-string "(foo :hello)"
                  {:bindings {'foo (fn [] 
                                    (println "foo is being evaluated from line "(:line (sci/get-context)) ))}})


Maybe there is. Let me check


Don't think so yes. But this ties a bit into another issue I'm solving at the moment, where I keep around a callstack of called functions in the interpreter. Would that help somehow here as well?


Maybe if the current symbol/function would be in the callstack and available via some kind of API. Then I would be able to save it in the context where the error might occur in the future


I’ll think about it a bit and maybe hack it into Sci to see how it could work exactly


This branch has a work in progress callstack: The callstack is accessible in with @sci.impl.vars/callstack. It's currently implementation detail because I don't know exactly yet how things are going to look. This is a fix to a wrong file name location reported with babashka (see issue 508).


But I was thinking this would also be useful in babashka/sci errors in general, to print the interpreter callstack with locations.


Looks useful indeed! And I think the implementation for what I need would look similar. I would mostly need :line and :column to print a nice error. (I’ve copied Figwheels error reporting approach to have an intuitive error)


I use it like this now. Lots of room for improvement still, but it’s already super handy


> And I think the implementation for what I need would look similar. So you would only need the line and symbol from the latest invoked function right? So something like (first @sci.core/callstack) which would give {:var foo/bar :line 1 :column 10}?


Yes I think that would be enough. it would need to be the function that is currently being invoked, not after it has been invoked


well, the currently invoked function would be the one on top of the stack

👌 1

anyway, I'll poke you when I have this done so you can test it for your purposes