diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 167cad4..60902e1 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -36,7 +36,7 @@ The Tao of Hy The following illustrates a brief list of design decisions that went into the making of Hy. -+ Look like a Lisp; DTRT with it (e.g. dashes turn to underscores). ++ Look like a Lisp; do the right thing with it (e.g. dashes turn to underscores). + We're still Python. Most of the internals translate 1:1 to Python internals. + Use Unicode everywhere. + When in doubt, defer to Python. @@ -49,126 +49,952 @@ into the making of Hy. Layout & Indentation ==================== -+ Avoid trailing spaces. They suck! +The #1 complaint about Lisp? -+ Indentation shall be 2 spaces (no hard tabs), except when matching - the indentation of the previous line. + *It's too weird looking with all those parentheses! How do you even* **read** *that?* - .. code-block:: clj +And, they're right! Lisp was originally much too hard to read. +Then they figured out layout and indentation. And it was glorious. - ;; Good (and preferred) - (defn fib [n] - (if (<= n 2) - n - (+ (fib (- n 1)) (fib (- n 2))))) +The Three Laws +-------------- - ;; Still okay - (defn fib [n] - (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) +Here's the secret: *Real Lispers don't count the brackets.* +They fade into the background. +When reading Lisp, disregard the trailing closing brackets---those are for the computer, not the human. +As in Python, read the code structure by indentation. - ;; Still okay - (defn fib [n] - (if (<= n 2) - n - (+ (fib (- n 1)) (fib (- n 2))))) +Lisp code is made of trees---Abstract Syntax Trees---not strings. +S-expressions are very direct textual representation of AST. +That's the level of *homoiconicity*---the level Lisp macros operate on. +It's not like the C-preprocessor or Python's interpolated eval-string tricks that see code as just letters. +That's not how to think of Lisp code; think tree structure, not delimiters. - ;; Hysterically ridiculous - (defn fib [n] - (if (<= n 2) - n ;; yes, I love randomly hitting the space key - (+ (fib (- n 1)) (fib (- n 2))))) +1. Closing brackets must NEVER be left alone, sad and lonesome on their own line. +.. code-block:: clj -+ Parentheses must *never* be left alone, sad and lonesome on their own - line. - - .. code-block:: clj - - ;; Good (and preferred) + ;; PREFERRED (defn fib [n] (if (<= n 2) n - (+ (fib (- n 1)) (fib (- n 2))))) + (+ (fib (- n 1)) + (fib (- n 2))))) ; Lots of Irritating Superfluous Parentheses + ; L.I.S.P. ;)) - ;; Hysterically ridiculous - (defn fib [n] + ;; How the experienced Lisper sees it. Indented trees. Like Python. + (defn fib [n + (if (<= n 2 + n + (+ (fib (- n 1 + (fib (- n 2 + + ;; BAD + ;; We're trying to ignore them and you want to give them their own line? + ;; Hysterically ridiculous. + (defn fib [ + n + ] ; My eyes! (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))) ) - ) ; GAH, BURN IT WITH FIRE + ) ; GAH, BURN IT WITH FIRE! - -+ Inline comments shall be two spaces from the end of the code; they - must always have a space between the comment character and the start - of the comment. Also, try to not comment the obvious. +2. New lines must ALWAYS be indented past their parent opening bracket. .. code-block:: clj - ;; Good - (setv ind (dec x)) ; indexing starts from 0 + ;; PREFERRED + (foo (, arg1 + arg2)) - ;; Style-compliant but just states the obvious - (setv ind (dec x)) ; sets index to x-1 + ;; BAD. And evil. + ;; Same bracket structure as above, but not enough indent. + (foo (, arg1 + arg2)) - ;; Bad - (setv ind (dec x));typing words for fun + ;; PREFERRED. Same indent as above, but now it matches the brackets. + (fn [arg] + arg) + ;; Remember, when reading Lisp, you ignore the trailing brackets. + ;; Look at what happens if we remove them. + ;; Can you tell where they should go by the indentation? + + (foo (, arg1 + arg2 + + (foo (, arg1 + arg2 + + (fn [arg + arg + + ;; See how the structure of those last two became indistinguishable? + + ;; Reconstruction of the bad example by indent. + ;; Not what we started with, is it? + (foo (, arg1) + arg2) + + ;; Beware of brackets with reader syntax. + ;; You still have to indent past them. + + ;; BAD + `#{(foo) + ~@[(bar) + 1 2]} + + ;; Above, no trail. + `#{(foo + ~@[(bar + 1 2 + + ;; Reconstruction. Is. Wrong. + `#{(foo)} + ~@[(bar)] + 1 2 + + ;; PREFERRED + `#{(foo) + ~@[(bar) + 1 + 2]} + + ;; OK + ;; A string is an atom, not a HySequence. + (foo "abc + xyz") + + ;; Still readable without trailing brackets. + (foo "abc + xyz" ; Double-quote isn't a closing bracket. Don't ignore it. + +3. New lines must NEVER be indented past the previous element's opening bracket. + +.. code-block:: clj + + ;; BAD + ((get-fn q) + x + y) + + ;; The above with trailing brackets removed. See the problem? + ((get-fn q + x + y + + ;; By indentation, this is where the brackets should go. + ((get-fn q + x + y)) + + ;; OK + ((get-fn q) x + y) + + ;; The above without trailing brackets. Still OK (for humans). + ((get-fn q) x ; The ) on this line isn't trailing! + y + + ;; PREFERRED, since the ) should end the line. + ((get-fn q) + x + y) + +Limits +------ + +Follow PEP 8 rules for line limits, viz. + + + 72 columns max for text (docstrings and comments). + + 79 columns max for other code, OR + + 99 for other code if primarily maintained by a team that can agree to 99. + +Whitespace +---------- + +AVOID trailing spaces. They suck! + +AVOID tabs in code. Indent with spaces only. + +PREFER the ``\t`` escape sequence to literal tab characters in one-line string literals. + + + Literal tabs are OK inside multiline strings if you also add a warning comment. + + But ``\t`` is still PREFERRED in multiline strings. + + The comment should PREFERABLY appear just before the string. + + But a blanket warning at the top of a function, class, or file is OK. + +Alignment +--------- + +Line up arguments to function calls when splitting over multiple lines. + + + The first argument PREFERABLY stays on the first line with the function name, + + but may instead start on the next line indented one space past its parent bracket. + +.. code-block:: clj + + ;; PREFERRED. All args aligned with first arg. + (foofunction arg1 + (barfunction bararg1 + bararg2 + bararg3) ; Aligned with bararg1. + arg3) + + ;; BAD + (foofunction arg1 + (barfunction bararg1 + bararg2 ; Wrong. Looks like a macro body. + bararg3) ; Why?! + arg3) + + ;; PREFERRED. Args can all go on one line if it fits. + (foofunction arg1 + (barfunction bararg1 bararg2 bararg3) + arg3) + + ;; OK. Args not on first line, but still aligned. + (foofunction + arg1 ; Indented one column past parent ( + (barfunction + bararg1 ; Indent again. + bararg2 ; Aligned with bararg1. + bararg3) + arg3) ; Aligned with arg1. + +Hold it Open +------------ + +If you need to separate a bracket trail use a ``#_ /`` comment to hold it open. +This avoids violating law #1. + +.. code-block:: clj + + ;; PREFERRED + [(foo) + (bar) + (baz)] + + ;; OK, especially if the list is long. (Not that three is long.) + ;; This is better for version control line diffs. + [ ; Opening brackets can't be "trailing closing brackets" btw. + (foo) + (bar) + (baz) + #_ /] ; Nothing to see here. Move along. + + ;; Examples of commenting out items at the end of a list follow. + ;; As with typing things in the REPL, these cases are less important + ;; if you're the only one that sees them. But even so, maintaining + ;; good style can help prevent errors. + + ;; BAD and a syntax error. Lost a bracket. + [(foo) + ;; (bar) + ;; (baz)] + + ;; BAD. Broke law #1. + [(foo) + ;; (bar) + ;; (baz) + ] + + ;; PREFERRED + ;; The discard syntax respects code structure, + ;; so it's less likely to cause errors. + [(foo) + #_(bar) + #_(baz)] + + ;; OK. Adding a final discarded element makes line comments safer. + [(foo) + ;; (bar) + ;; (baz) + #_ /] + +Snuggle +------- + +Brackets like to snuggle, don't leave them out in the cold! + +.. code-block:: clj + + ;; PREFERRED + [1 2 3] + (foo (bar 2)) + + ;; BAD + [ 1 2 3 ] + ( foo ( bar 2 ) ) + + ;; BAD. And ugly. + [ 1 2 3] + (foo( bar 2) ) + +Grouping +-------- + +Use whitespace to show implicit groups, but be consistent within a form. + +.. code-block:: clj + + ;; Older Lisps would typically wrap such groups in even more parentheses. + ;; (The Common Lisp LOOP macro was a notable exception.) + ;; But Hy takes after Clojure, which has a lighter touch. + + ;; BAD. Can't tell key from value without counting + {1 9 2 8 3 7 4 6 5 5} + + ;; PREFERRED. This can fit on one line. Clojure would have used commas + ;; here, but those aren't whitespace in Hy. Use extra spaces instead. + {1 9 2 8 3 7 4 6 5 5} + + ;; OK. And preferred if it couldn't fit on one line. + {1 9 + 2 8 + 3 7 + 4 6 + 5 5} ; Newlines show key-value pairs in dict. + + ;; BAD + ;; This grouping makes no sense. + #{1 2 + 3 4} ; It's a set, so why are there pairs? + + ;; BAD + ;; This grouping also makes no sense. But, it could be OK in a macro or + ;; something if this grouping was somehow meaningful there. + [1 + 1 2 + 1 2 3] ; wHy do you like random patterns? [sic pun, sorry] + + ;; Be consistent. Separate all groups the same way in a form. + + ;; BAD + {1 9 2 8 + 3 7 4 6 5 5} ; Pick one or the other! + + ;; BAD + {1 9 2 8 3 7 4 6 5 5} ; You forgot something. + + ;; Groups of one must also be consistent. + + ;; PREFERRED + (foo 1 2 3) ; No need for extra spaces here. + + ;; OK, but you could have fit this on one line. + (foo 1 + 2 + 3) + + ;; OK, but you still could have fit this on one line. + [1 + 2] + + ;; BAD + (foo 1 2 ; This isn't a pair? + 3) ; Lines or spaces--pick one or the other! + + ;; PREFERRRED + (foofunction (make-arg) + (get-arg) + #tag(do-stuff) ; Tags belong with what they tag. + #* args ; #* goes with what it unpacks. + :foo spam + :bar eggs ; Keyword args are also pairs. Group them. + #** kwargs) + + ;; PREFERRED. Spaces divide groups on one line. + (quux :foo spam :bar eggs #* with-spam) + {:foo spam :bar eggs} + + ;; OK. The colon is still enough to indicate groups. + (quux :foo spam :bar eggs #* with-spam) + {:foo spam :bar eggs} + ;; OK. + ("foo" spam "bar" eggs} + + ;; BAD. Can't tell key from value. + (quux :foo :spam :bar :eggs :baz :bacon) + {:foo :spam :bar :eggs :baz :bacon} + {"foo" "spam" "bar" "eggs" "baz" "bacon"} + + ;; PREFERRED + (quux :foo :spam :bar :eggs :baz :bacon) + {:foo :spam :bar :eggs :baz :bacon} + {"foo" "spam" "bar" "eggs" "baz" "bacon"} + + ;; OK. Yep, those are pairs too. + (setv x 1 + y 2) + + ;; PREFERRED. This fits on one line. + (setv x 1 y 2) + + ;; BAD. Doesn't separate groups. + (print (if (< n 0.0) + "negative" + (= n 0.0) + "zero" + (> n 0.0) + "positive" + "not a number")) + + ;; BAD. And evil. Broke law #3. Shows groups but args aren't aligned. + (print (if (< n 0.0) + "negative" + (= n 0.0) + "zero" + (> n 0.0) + "positive" + "not a number")) + + ;; BAD. Shows groups but args aren't aligned. + ;; If the then-parts weren't atoms, this would break law #3. + (print (if (< n 0.0) + "negative" + (= n 0.0) + "zero" + (> n 0.0) + "positive" + "not a number")) + + ;; OK. Redundant (do) forms allow extra indent to show groups + ;; without violating law #3. + (print (if (< n 0.0) + (do + "negative") + (= n 0.0) + (do + "zero") + (> n 0.0) + (do + "positive") + "not a number")) + +Separate toplevel forms (including toplevel comments not about a particular form) +with a single blank line, rather than two as in Python. + + + This can be omitted for tightly associated forms. + +Methods within a defclass need not be separated by blank line. + +Special Arguments +----------------- + +Macros and special forms are normally indented one space past the parent bracket, +but can also have "special" arguments that are indented like function arguments. + + + Macros with an ``&rest body`` argument contain an implicit ``do``. + + The body is never special, but the arguments before it are. + +.. code-block:: clj + + ;; PREFERRED + (assoc foo ; foo is special + "x" 1 ; remaining args are not special. Indent 2 spaces. + "y" 2) + + ;; PREFERRED + ;; The do form has no special args. Indent like a function call. + (do (foo) + (bar) + (baz)) + + ;; OK + ;; No special args to distinguish. This is also valid function indent. + (do + (foo) + (bar) + (baz)) + + ;; PREFERRED + (defn fib [n] + (if (<= n 2) + n + (+ (fib (- n 1)) + (fib (- n 2))))) + + ;; OK + (defn fib + [n] ; name and argslist are special. Indent like function args. + ;; The defn body is not special. Indent 1 space past parent bracket. + (if (<= n 2) + n + (+ (fib (- n 1)) ; Emacs-style else indent. + (fib (- n 2))))) + +Removing Whitespace +------------------- + +Removing whitespace can also make groups clearer. + +.. code-block:: clj + + ;; lookups + + ;; OK + (. foo ["bar"]) + + ;; PREFERRED + (. foo["bar"]) + + ;; BAD. Doesn't show groups clearly. + (import foo foo [spam :as sp eggs :as eg] bar bar [bacon]) + + ;; OK. Extra spaces show groups. + (import foo foo [spam :as sp eggs :as eg] bar bar [bacon]) + + ;; PREFERRED. Removing spaces is even clearer. + (import foo foo[spam :as sp eggs :as eg] bar bar[bacon]) + + ;; OK. Newlines show groups. + (import foo + foo [spam :as sp + eggs :as eg] + bar + bar [bacon]) + + ;; PREFERRED, It's more consistent with the preferred one-line version. + (import foo + foo[spam :as sp + eggs :as eg] + bar + bar[bacon]) + + ;; Avoid whitespace after tags. + + ;; Note which shows groups better. + + ;; BAD + (foofunction #tag "foo" #tag (foo) #* (get-args)) + + ;; OK + (foofunction #tag "foo" #tag (foo) #* (get-args)) + + ;; PREFERRED + (foofunction #tag"foo" #tag(foo) #*(get-args)) + + ;; PREFERRED + ;; Can't group these by removing whitespace. Use extra spaces instead. + (foofunction #x foo #x bar #* args) + + ;; OK + ;; Same idea, but this could have fit on one line. + (foofunction #x foo + #x bar + #* args) + + ;; OK, but you don't need to separate function name from first arg. + (foofunction #x foo #x bar #* args) + + ;; OK. But same idea. + ;; No need to separate the first group from the function name. + (foofunction + #x foo + #x bar + #* args) + + ;; PREFERRED. It's still clear what this is tagging. + ;; And you don't have to re-indent. + #_ + (def foo [] + stuff) + + ;; OK, but more work. + #_(def foo [] + stuff) + + ;; BAD, you messed up the indent and broke law #2. + #_(def foo [] + stuff) + + ;; BAD, keep the tag grouped with its argument. + #_ + + (def foo [] + stuff) + +Close Bracket, Close Line +------------------------- + +A *single* closing bracket SHOULD end the line, +unless it's in the middle of an implicit group. + + + If the forms are small and simple you can maybe leave them on one line. + +A *train* of closing brackets MUST end the line. + +.. code-block:: clj + + ;; One-liners are overrated. + ;; Maybe OK if you're just typing into the REPL. + ;; But even then, maintaining good style can help prevent errors. + + ;; BAD. One-liner is too hard to read. + (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) + + ;; BAD. Getting better, but the first line is still too complex. + (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) + (fib (- n 2))))) + ;; OK. Barely. + (defn fib [n] + (if (<= n 2) n (+ (fib (- n 1)) ; This line is pushing it. + (fib (- n 2))))) + + ;; OK + (defn fib [n] ; Saw a "]", newline. + (if (<= n 2) ; OK to break here, since there's only one pair. + n + (+ (fib (- n 1)) ; Whitespace separation (Emacs else-indent). + (fib (- n 2))))) + + ;; OK + (defn fib [n] ; Saw a "]", end line. (Margin comments don't count.) + (if (<= n 2) n ; Saw a ")", but it's in a pair starting in this line. + (+ (fib (- n 1)) ; Saw a "))" MUST end line. + (fib (- n 2))))) + + ;; OK. Pairs. + (print (if (< n 0.0) "negative" ; Single ) inside group. No break. + (= n 0.0) "zero" + (> n 0.0) "positive" + :else "not a number")) ; :else is not magic; True works too. + + ;; OK. Avoided line breaks at single ) to show pairs. + (print (if (< n 0.0) "negative" + (= n 0.0) "zero" + (> n 0.0) (do (do-foo) ; Single ) inside group. No break. + (do-bar) + "positive") + "not a number")) ; Implicit else is PREFERRED. + + ;; BAD + (print (if (< n 0.0) "negative" + (= n 0.0) "zero" + (and (even? n) + (> n 0.0)) "even-positive" ; Bad. "))" must break. + (> n 0.0) "positive" + "not a number")) + + ;; BAD + (print (if (< n 0.0) "negative" + (= n 0.0) "zero" + (and (even? n) + (> n 0.0)) (do (do-foo) ; Y U no break? + (do-bar) + "even-positive") + (> n 0.0) "positive" + "not a number")) + + ;; OK. Blank line separates multiline groups. + (print (if (< n 0.0) "negative" + + (= n 0.0) "zero" + + (and (even? n) + (> n 0.0)) + (do (do-foo) + (do-bar) + "even-positive") + + (> n 0.0) "positive" + + "not a number")) + + ;; BAD. Groups are not separated consistently. + (print (if (< n 0.0) "negative" + (= n 0.0) "zero" + + (> n 0.0) + (do (do-foo) + "positive") + + "not a number")) + + ;; OK. Single )'s and forms are simple enough. + (with [f (open "names.txt")] + (-> (.read f) .strip (.replace "\"" "") (.split ",") sorted))) + + ;; PREFERRED. Even so, this version is much clearer. + (with [f (open "names.txt")] + (-> (.read f) + .strip + (.replace "\"" "") + (.split ",") + sorted))) + +Comments +-------- + +Prefer docstrings to comments where applicable---in ``fn``, ``defclass``, +at the top of the module, and in any other macros derived from these that can take a docstring +(e.g. ``defmacro/g!``, ``deftag``, ``defn``). + +Docstrings contents follow the same conventions as Python. + +The ``(comment)`` macro is still subject to the three laws. +If you're tempted to violate them, consider discarding a string instead with ``#_``. + +Semicolon comments always have one space between the semicolon and the start of the comment. +Also, try to not comment the obvious. + +Comments with more than a single word should start with a capital letter and use punctuation. + +Separate sentences with a single space. + +.. code-block:: clj + + ;; This commentary is not about a particular form. + ;; These can span multiple lines. Limit them to column 72, per PEP 8. + ;; Separate them from the next form or form comment with a blank line. + + ;; PREFERRED. + (setv ind (dec x)) ; Indexing starts from 0, + ; margin comment continues on new line. + + ;; OK + ;; Style-compliant but just states the obvious. + (setv ind (dec x)) ; Sets index to x-1. + + ;; BAD + (setv ind (dec x));typing words for fun + + ;; Comment about the whole foofunction call. + ;; These can also span mulitple lines. + (foofunction ;; Form comment about (get-arg1). Not a margin comment! + (get-arg1) + ;; Form comment about arg2. The indent matches. + arg2) + +Indent form comments at the same level as the form they're commenting about; +they must always start with exactly two semicolons ``;;``. +Form comments appear directly above what they're commenting on, never below. + +General toplevel commentary is not indented; +these must always start with exactly two semicolons ``;;`` +and be separated from the next form with a blank line. +For long commentary, consider using a ``#_`` applied to a string for this purpose instead. + +Margin comments start two spaces from the end of the code; they +must always start with a single semicolon ``;``. +Margin comments may be continued on the next line. + +When commenting out entire forms, prefer the ``#_`` syntax. +But if you do need line comments, use the more general double-colon form. Coding Style ============ -+ Do not use s-expression syntax where vector syntax is intended. - For instance, the fact that the former of these two examples works - is just because the compiler isn't overly strict. In reality, the - correct syntax in places such as this is the latter. +Pythonic Names +-------------- - .. code-block:: clj +Use Python's naming conventions where still applicable to Hy. - ;; Bad (and evil) - (defn foo (x) (print x)) - (foo 1) + + The first parameter of a method is ``self``, + + of a classmethod is ``cls``. - ;; Good (and preferred) - (defn foo [x] (print x)) - (foo 1) +Threading Macros +---------------- + +PREFER the threading macro or the threading tail macros when encountering +deeply nested s-expressions. However, be judicious when using them. Do +use them when clarity and readability improves; do not construct +convoluted, hard to understand expressions. + +.. code-block:: clj + + ;; BAD. Not wrong, but could be much clearer with a threading macro. + (setv NAMES + (with [f (open "names.txt")] + (sorted (.split (.replace (.strip (.read f)) + "\"" + "") + ",")))) + + ;; PREFERRED. This compiles exactly the same way as the above. + (setv NAMES + (with [f (open "names.txt")] + (-> (.read f) + .strip + (.replace "\"" "") + (.split ",") + sorted))) + + ;; BAD. Probably. The macro makes it less clear in this case. + (defn square? [x] + (->> 2 + (pow (int (sqrt x))) + (= x))) + + ;; OK. Much clearer that the previous example above. + (defn square? [x] + (-> x + sqrt + int + (pow 2) + (= x)) + + ;; PREFERRED. Judicious use. + ;; You don't have to thread everything if it improves clarity. + (defn square? [x] + (= x (-> x sqrt int (pow 2)))) + + ;; OK. Still clear enough with no threading macro this time. + (defn square? [x] + (= x (pow (int (sqrt x)) ; saw a "))", break. + 2)) ; aligned with first arg to pow -+ Use the threading macro or the threading tail macros when encountering - deeply nested s-expressions. However, be judicious when using them. Do - use them when clarity and readability improves; do not construct - convoluted, hard to understand expressions. +Method Calls +------------ - .. code-block:: clj +Clojure-style dot notation is PREFERRED over the direct call of +the object's method, though both will continue to be supported. - ;; Preferred - (setv *names* - (with [f (open "names.txt")] - (-> (.read f) (.strip) (.replace "\"" "") (.split ",") (sorted)))) +.. code-block:: clj - ;; Not so good - (setv *names* - (with [f (open "names.txt")] - (sorted (.split "," (.replace "\"" "" (.strip (.read f))))))) - - ;; Probably not a good idea - (setv square? [x] - (->> 2 (pow (int (sqrt x))) (= x))) - - -+ Clojure-style dot notation is preferred over the direct call of - the object's method, though both will continue to be supported. - - .. code-block:: clj - - ;; Good + ;; PREFERRED (with [fd (open "/etc/passwd")] (print (.readlines fd))) - ;; Not so good + ;; OK (with [fd (open "/etc/passwd")] (print (fd.readlines))) +Use More Arguments +------------------ + +PREFER using multiple arguments to multiple forms. +But judicious use of redundant forms can clarify intent. +AVOID the separating blank line for toplevel forms in this case. + +.. code-block:: clj + + ;; BAD + (setv x 1) + (setv y 2) + (setv z 3) + (setv foo 9) + (setv bar 10) + + ;; OK + (setv x 1 + y 2 + z 3 + foo 9 + bar 10) + + ;; PREFERRED + (setv x 1 + y 2 + z 3) + (setv foo 9 + bar 10) + +Imports +------- + +As in Python, group imports. + + + Standard library imports (including Hy's) first. + + Then third-party modules, + + and finally internal modules. + +PREFER one import form for each group. + +PREFER alphabetical order within groups. + +Require macros before any imports and group them the same way. + +But sometimes imports are conditional or must be ordered a certain way for programmatic reasons, which is OK. + +.. code-block:: clj + + ;; PREFERRED + (require hy.extra.anaphoric [%]) + (require thirdparty [some-macro]) + (require mymacros [my-macro]) + + (import json re) + (import numpy :as np + pandas :as pd) + (import mymodule1) + +Underscores +----------- + +Prefer hyphens when separating words. + ++ PREFERRED ``foo-bar`` ++ BAD ``foo_bar`` + +Don't use leading hyphens, except for "operators" or symbols meant to be read as including one, +e.g. ``-Inf``, ``->foo``. + +Prefix private names with an underscore, not a dash. +to avoid confusion with negated literals like ``-Inf``, ``-42`` or ``-4/2``. + ++ PREFERRED ``_x`` ++ BAD ``-x`` + +Write Python's magic "dunder" names the same as in Python. +Like ``__init__``, not ``--init--`` or otherwise, +to be consistent with the private names rule above. + +Private names should still separate words using dashes instead of underscores, +to be consistent with non-private parameter names and such that need the same name sans prefix, +like ``foo-bar``, not ``foo_bar``. + ++ PREFERRED ``_foo-bar`` ++ BAD ``_foo_bar`` + + +.. code-block:: clj + + ;; BAD + ;; What are you doing? + (_= spam 2) ; Throwing it away? + (_ 100 7) ; i18n? + + ;; PREFERRED + ;; Clearly subtraction. + (-= spam 2) + (- 100 7) + + ;; BAD + ;; This looks weird. + (_>> foo bar baz) + + ;; PREFERRED + ;; OH, it's an arrow! + (->> foo bar baz) + + ;; Negative x? + (setv -x 100) ; BAD. Unless you really meant that? + + ;; PREFERRED + ;; Oh, it's just a module private. + (setv _x 100) + + ;; BAD + (class Foo [] + (defn __init-- [self] ...)) + + ;; OK + (class Foo [] + ;; Less weird? + (defn --init-- [self] ...)) + + ;; PREFERRED + (class Foo [] + (defn __init__ [self] ...)) + + ;; OK, but would be module private. (No import *) + (def ->dict [&rest pairs] + (dict (partition pairs))) Conclusion ========== @@ -178,18 +1004,27 @@ Conclusion This guide is just a set of community guidelines, and obviously, community -guidelines do not make sense without an active community. Contributions are -welcome. Join us at #hy in freenode, blog about it, tweet about it, and most -importantly, have fun with Hy. +guidelines do not make sense without an active community. +As in Python, we expect the style of Hy to be refined over time in practice. +Contributions are welcome. +Join us at #hy in freenode, blog about it, +tweet about it, and most importantly, have fun with Hy. Thanks ====== -+ This guide is heavily inspired from `@paultag`_ 's blog post `Hy - Survival Guide`_ ++ This guide is heavily inspired from `@paultag`_ 's blog post `Hy Survival Guide`_ + The `Clojure Style Guide`_ ++ `Parinfer`_ and `Parlinter`_ (the three laws) ++ The Community Scheme Wiki `scheme-style`_ (ending bracket ends the line) ++ `Riastradh's Lisp Style Rules`_ (Lisp programmers do not ... Azathoth forbid, count brackets) .. _`Hy Survival Guide`: https://notes.pault.ag/hy-survival-guide/ .. _`Clojure Style Guide`: https://github.com/bbatsov/clojure-style-guide .. _`@paultag`: https://github.com/paultag +.. _`Parinfer`: https://shaunlebron.github.io/parinfer/ +.. _`Parlinter`: https://github.com/shaunlebron/parlinter +.. _`scheme-style`: http://community.schemewiki.org/?scheme-style +.. _`Comment-Tips`: https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html +.. _`Riastradh's Lisp Style Rules`: http://mumble.net/~campbell/scheme/style.txt