clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
zimablue 2021-04-25T07:18:04.030100Z

is it idiomatic to create a record with no fields as the equivalent of what I'd use a python (implicitly static) class for - a quasi-namespace grouping related functionality?

borkdude 2021-04-25T07:27:37.030500Z

@zimablue can you give an example of how you use it?

borkdude 2021-04-25T07:28:52.030800Z

If you need a marker interface you can also use definterface

zimablue 2021-04-25T07:30:32.032600Z

in interactive development, often around manipulating data like data munging, in python my workflow is like (mess with in repl) => (end up with lots of functions) => (throw those functions into static python classes grouped by area) => (refactor into some static classes, some normal classes, some loose functions)

zimablue 2021-04-25T07:31:14.033500Z

so right now I'm messing with a git diff and I'd probably throw the functions I've some up with into a couple of static classes if I was in python, split by "upstream" and "downstream" processing

borkdude 2021-04-25T07:31:48.034400Z

In clojure you usually use a namespace. why not use one?

zimablue 2021-04-25T07:31:54.034500Z

being a clojure noob I don't get the idiomatic equivalent, from the linked stackoverflow it seems that what I'd normally do is funky since it would require creating protocols for no reason, and I need to use like a raw map

2021-04-25T07:32:01.034900Z

No need for extra wrapping, just defn them in the namespace

zimablue 2021-04-25T07:32:35.035700Z

because the unit of grouping and formality is lower, each namespace should be in it's own file? I could do that but it's a bit more ceremony and slightly more complication than static classes would be

zimablue 2021-04-25T07:32:48.036200Z

not a big deal, sorry I'm new-ish to clojure so overthinking stuff probably

borkdude 2021-04-25T07:33:00.036600Z

If you want to subdivide functions within a namespace, some people use conventions like

(defn foo:bar1 [])
(defn foo:bar2 [])

zimablue 2021-04-25T07:33:07.036800Z

interesting

zimablue 2021-04-25T07:33:17.037100Z

thanks, that's an example of solving the same sort of problem I think

zimablue 2021-04-25T07:33:21.037300Z

just rough organization

zimablue 2021-04-25T07:33:36.037600Z

I could just split the files, it's not a big deal maybe, just feels like overkill

zimablue 2021-04-25T07:36:06.038300Z

ok sounds like my three options: just use ordering/naming conventions, do something clever with maps/macros, just use namespaces

zimablue 2021-04-25T07:36:16.038700Z

I'm not missing some perfect abstraction for my use-case hopefully

alexmiller 2021-04-25T14:09:15.040200Z

The feature in Clojure for grouping and naming functions is namespaces

2021-04-25T14:12:27.042100Z

I guess one question to ask about the practice you have developed in Python is: for what reason do you want to collect multiple Python functions in a Python 'static class'? Why did you do that, vs. put those Python functions at the top level in your source file? Clojure functions at the top level in a namespace seem to correspond closely with Python functions defined at the top level, certainly. There isn't a direct analog in Clojure of creating a static class that is there for nothing but containing methods, but it naturally leads to the question of "why bother creating such a class?"

emccue 2021-04-25T17:18:50.043700Z

@zimablue one thing that can be useful is to design functions such that they are meant to be used with a namespace alias

emccue 2021-04-25T17:19:02.043900Z

so like instead of

emccue 2021-04-25T17:25:40.048Z

(ns your-project.stack)

(defn stack-create []
  '())

(defn stack-pop [stack]
  [(first stack) (rest stack)])

(defn stack-push [stack item]
  (cons item q))

(ns other-ns
  (:require [your-project.stack :refer [stack-create stack-pop stack-push]]))

(let [stack1 (-> (stack-create)
                 (stack-push 1)
                 (stack-push 2))
      [head stack2] (stack-pop stack1)]
  ...)

emccue 2021-04-25T17:25:43.048200Z

you do

emccue 2021-04-25T17:26:37.049Z

(ns your-project.stack)

(defn create []
  '())

(defn pop [stack]
  [(first stack) (rest stack)])

(defn push [stack item]
  (cons item q))

(ns other-ns
  (:require [your-project.stack :as stack]))

(let [stack1 (-> (stack/create)
                 (stack/push 1)
                 (stack/push 2))
      [head stack2] (stack/pop stack1)]
  ...)

emccue 2021-04-25T17:27:52.049900Z

if you want object-ey things, this is a decent way - a protocol and a defrecord isn't strictly needed unless you want the dispatch bits of it

Xarlyle0 2021-04-25T18:55:03.050500Z

Same as @markbastian except with Mount instead of Integrant.