I fear this reads not very precise, mostly arbitrary and random.
Examples:
> If a value is an arbitrary Clojure expression, it should be called form. If a macro takes many expressions, the variadic parameters should be called body.
A value is an expression? what is a Clojure 'expression'? Why should it be called a 'form'? If it is arbitrary, why not call it 'expression'? What does it mean to 'take an expression'? What is 'many'? A macro, the variadic parameterS, which should be called 'body'? The macro has more than one variadic parameter and they all should be called 'body'?
> These defaults derive from the idioms of the Clojure ecosystem and common sense.
'Common sense'? What?
> If a value can be anything, we should call it x. This is fairly rare, as usually the only things we can do with an object involve =, hash, and str.
What is a value? what is 'anything'? The next sentence talks about 'objects'. Is 'anything' always an object? Why don't we talk about 'any object', instead of 'anything'? What does the number of possible actions have to do how 'rare' a name is?
> Let’s consider a student datatype, which is represented as a map whose keys and values are well defined, either using documentation or a formal schema. Anything called student should have at least these entries, and sometimes only these entries.
A data type is 'represented' by a map? What does that even mean? 'Anything'? What is 'anything' in this context and what means 'entry' in this context?
This goes on and on.
> At runtime, our scope is any data we can see from within our thread.
What is this 'we' at runtime and what does it mean for 'we' to 'see' data?
> Conversely, we can think of sending an HTTP request as sailing across an ocean; any transfer of data, pushed or pulled, requires effort.
What?
> If a function crosses scope boundaries, there should be a verb in the name. If it pulls data, it should describe the datatype it returns.
What does it mean for a function to cross scope boundaries? What is a scope boundary?
> There are two kinds of macros: those which we understand syntactically, and those which we understand semantically.
There are two kinds of macros, those who begin with WITH and those who do not. What does it mean to 'understand syntactically'/'semantically'?
> To use with-open effectively, we must macroexpand it in our heads whenever it appears in the code.
what?
> syntactic macros
What is that exactly?
> Transforming arbitrary code is difficult and sometimes impossible
What?
Macros: ...
> Readers must not only understand the semantics of the transformation, but also its exceptions and failure modes.
Personally I, as a reader, am more interested in the semantics of the generated code.
> macroexpanded syntax
How can I macroexpand syntax?
> Naming is a problem which cannot be solved, but also cannot be ignored.
What kind of problem is it and why can't it be solved. But then I can not ignore it? It can't be solved, but I can not ignore it?
Worse: much of the advice assumes a static text program where the only option I have is to read the text. Not a Lisp system with data<->code.
Probably also a good idea to write a glossary, where the basic terms (form, value, expression, scope, scope boundary, data, parameter, argument, variadic argument, syntactic macro, failure mode, ...) are defined/described.
Without a hint of irony: thank you for reading this so carefully. Some of the things you note are typos or poorly worded, most are things that I think are clear in context. In either case, yours is one of the very few comments about the actual book, rather than Clojure in general. I appreciate it.
> To use with-open effectively, we must macroexpand it in our heads whenever it appears in the code.
I'd like to add that if you find yourself needing to mentally expand a macro every time you use/read it, you have a poor abstraction. Consider going back to the drawing board and coming up with a good abstraction instead.
For a macro which only implements a 'simple' syntactic transformation, I would expect that I need to understand the semantics anyway. Additionally I need to understand the syntax it implements.
What I don't want at all, is to macroexpand macro forms. If I need to macroexpand those, then I would do this for debugging, when there is something wrong during expansion or with the generated code. I would also do the expansion not in my head, but using a function called 'macroexpand'.
For example as a reader, I don't want to macroexpand the following form in my head:
(with-open-file (foo "bar.text")
(read foo))
What I really want is to understand the syntax of WITH-OPEN-FILE and semantics of such a form. To what it transforms itself is the least important thing I (as a code reader) want to know when dealing with macro forms.
* it's a WITH- type macro which sets up a scope.
* a WITH- type macro usually expects a variable, something which helps creating an object that is bound to the variable and a bunch of options
(foo-var "the-file-name.text" :direction :input)
* it then expects a body, a sequence of forms, where the variable FOO-VAR is bound to a file
That's the syntax.
The semantics is that at runtime it opens a file as a stream and makes sure that on all forms of exit, the stream gets closed.
To what form this actually expands (even if it is a simple transformation) is uninteresting and may be different from implementation to implementation.
Examples:
> If a value is an arbitrary Clojure expression, it should be called form. If a macro takes many expressions, the variadic parameters should be called body.
A value is an expression? what is a Clojure 'expression'? Why should it be called a 'form'? If it is arbitrary, why not call it 'expression'? What does it mean to 'take an expression'? What is 'many'? A macro, the variadic parameterS, which should be called 'body'? The macro has more than one variadic parameter and they all should be called 'body'?
> These defaults derive from the idioms of the Clojure ecosystem and common sense.
'Common sense'? What?
> If a value can be anything, we should call it x. This is fairly rare, as usually the only things we can do with an object involve =, hash, and str.
What is a value? what is 'anything'? The next sentence talks about 'objects'. Is 'anything' always an object? Why don't we talk about 'any object', instead of 'anything'? What does the number of possible actions have to do how 'rare' a name is?
> Let’s consider a student datatype, which is represented as a map whose keys and values are well defined, either using documentation or a formal schema. Anything called student should have at least these entries, and sometimes only these entries.
A data type is 'represented' by a map? What does that even mean? 'Anything'? What is 'anything' in this context and what means 'entry' in this context?
This goes on and on.
> At runtime, our scope is any data we can see from within our thread.
What is this 'we' at runtime and what does it mean for 'we' to 'see' data?
> Conversely, we can think of sending an HTTP request as sailing across an ocean; any transfer of data, pushed or pulled, requires effort.
What?
> If a function crosses scope boundaries, there should be a verb in the name. If it pulls data, it should describe the datatype it returns.
What does it mean for a function to cross scope boundaries? What is a scope boundary?
> There are two kinds of macros: those which we understand syntactically, and those which we understand semantically.
There are two kinds of macros, those who begin with WITH and those who do not. What does it mean to 'understand syntactically'/'semantically'?
> To use with-open effectively, we must macroexpand it in our heads whenever it appears in the code.
what?
> syntactic macros
What is that exactly?
> Transforming arbitrary code is difficult and sometimes impossible
What?
Macros: ... > Readers must not only understand the semantics of the transformation, but also its exceptions and failure modes.
Personally I, as a reader, am more interested in the semantics of the generated code.
> macroexpanded syntax
How can I macroexpand syntax?
> Naming is a problem which cannot be solved, but also cannot be ignored.
What kind of problem is it and why can't it be solved. But then I can not ignore it? It can't be solved, but I can not ignore it?
Worse: much of the advice assumes a static text program where the only option I have is to read the text. Not a Lisp system with data<->code.
Probably also a good idea to write a glossary, where the basic terms (form, value, expression, scope, scope boundary, data, parameter, argument, variadic argument, syntactic macro, failure mode, ...) are defined/described.