4 ms·
Agree about the dopamine flow from working with a good compiler/IDE. Golang's compiler is super fast and super fun, with very helpful messaging. Enjoyable refac
by jonahbenton 7y ago
Agree about the dopamine flow from working with a good compiler/IDE. Golang's compiler is super fast and super fun, with very helpful messaging. Enjoyable refactoring process, to be sure.
In terms of dynamic languages, the Clojure ecosystem has a lot of techniques that help with dynamic language codebase scalability. Very few are exhibited in Python codebases I see, I imagine for various reasons.
The most important is short, single purpose functions arranged in layers- essential for working at the REPL, where you may want to inspect or interject at any point in the data flow.
Related is a clear segregation between code and data, and explicit data flow/state control. I see this violated all the time in Python classes, which are very clever but should almost never be used.
Clojure Spec is also a revelation, much more expressive than a static type system and also (IMO) much more comprehensible. Nothing equivalent in the Python world.
Python works hard to be readable in the small, but it is a struggle in the large, both because the language does not help you and because the ecosystem is still pretty immature.
- j88439h84 7y agoI would love to see clojure spec in python.
- edflsafoiewq 7y ago> Related is a clear segregation between code and data, and explicit data flow/state control. I see this violated all the time in Python classes, which are very clever but should almost never be used. Could you expand on this one?
- jonahbenton 7y agoAppreciate the question. The crux of this observation is that the easy opportunity Python affords to create class-based encapsulations introduces a tension between a world where data flow and state is hidden, implicit, and private- in service of attempting to define precise type-like abstractions- and a world where data flow and state is explicit and public. Although Python does a lovely job in defining type-like protocols that classes can participate in- e.g. all the special dunder methods- most Python code in the wild that I see is not beautiful-in-the-large, well-developed, reusable, leverageable abstractions. It's just business logic, conditionals, utility code, scripts-turned-into-apps, etc. Plenty of reusable functions, very few reusable types. Putting business logic mush into classes with some state and calling it a type is a straight line to unmaintainability. It becomes very difficult to extend such a system with new "types" or to modify behavior of existing types, because there is a lack of clarity about the semantics of the existing types. Rather than trying to define types with state, much better to treat state as data- the difference is that the term state implies some special smart type-like semantics, while data is just dumb keys and values. The comparison I drew was with Clojure, which doesn't make it so easy to make classes that hide state or create fake types. Instead it has graduated options for lightly packaging data elements together- start with maps/dicts and move onto records- and optimizes for just chaining functions that operate on those data blobs. "Simple", as Rich Hickey famously says. There is no spaghetti-inducing tension between keeping logic "encapsulated" vs coding it "in the open." For regular line of business apps, the latter is so much better when it comes to maintainability, but the presence of classes provides a constant temptation to find reusability/encapsulation/abstraction where it doesn't actually exist. In Python, IMO, classes should only rarely be used. Hope that helps?
- m45t3r 7y agoI concur. I am writing a new project in Python after some months writing exclusively Clojure. I decided to write the code using small, pure functions and avoiding classes unless strictly necessary makes the codebase much easier to maintain in the long run. However I don't think the Python ecosystem is immature, for me it is the contrary. This project started with Python since I didn't find a good way to reduce the Clojure startup time, and believe me I tried everything I found (from GraalVM to ClojureScript). And there is gaps everywhere in Clojure ecosystem when you want to create command line tools, while Python has literally everything I needed.
- m45t3r 7y agoBTW, if there is anyway that I can get Clojure startup time below 0.1s (actually, until 0.2s wouldn't be so bad, but this is my limit) that doesn't involve something like a daemon running I would be all ears. I would really like "real" Clojure in this case (i.e.: not ClojureScript), since the ecosystem from Clojure is much better.
- novok 7y agoProbably not using clojure and using another lisp with a good startup time.
- deckiedan 7y agohttps://planck-repl.org/ https://planck-repl.org/ Might help? Clojurescript, but fast start up at least...
- m45t3r 7y agoPlanck/Lumo for actual projects are really slow and I don't know why (0.5s of startup time). For some reason, the REPL is fast, and I didn't investigate why REPL is fast and an actual project is slow.
- lispm 7y agoOther options like SBCL would allow this easily: $ echo "(format t \"Hello\!~%\")" | cat - > /tmp/test.lisp $ time sbcl --script /tmp/test.lisp Hello! real 0m0.014s Executables are easily created, though they are not small in SBCL. $ sbcl This is SBCL 1.5.9, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (sb-ext:save-lisp-and-die "howfast" :toplevel (lambda () (format t "Hello!~%")) :executable t) [undoing binding stack and other enclosing state... done] [performing final GC... done] [defragmenting immobile space... (fin,inst,fdefn,code,sym)=1026+935+18027+18435+25326... done] [saving current Lisp image into howfast: writing 0 bytes from the read-only space at 0x20000000 writing 432 bytes from the static space at 0x20100000 writing 26804224 bytes from the dynamic space at 0x1000000000 writing 1990656 bytes from the immobile space at 0x20300000 writing 11935744 bytes from the immobile space at 0x21b00000 done] $ time ./howfast Hello! real 0m0.016s