Re: An Error spec?

2018-10-26 Thread Benoît Fleury
I found the `cognitect.anomalies` namespace useful to provide some
uniformity in error codes and their meaning.

https://github.com/cognitect-labs/anomalies



On Fri, Oct 26, 2018 at 6:03 PM Oleksii Kachaiev  wrote:

> Sean, that's what I'm actually talking about.
>
> 1. There's no standard way to return "predictably" bad result. I don't
> know what you meant with "documented way through its return value". There's
> no Either with Left/Right (Scala, Haskell), no Result with Ok/Error (Rust),
> there's no "second value with an error" (Go) etc etc etc. You have to come
> up with your own way to distinguish bad and good result. And they will be
> different for different libraries. And that's right the problem I've stated
> in my message. No unification means manually work in each use case.
>
> 2. The standard library throws exceptions even when the error might be
> conveyed as the result of the call. Probably because of #1 - there's no way
> to express that.. Well... except exceptions. So, we're running circles here.
>
> BR,
>
> On Saturday, October 27, 2018 at 12:48:27 AM UTC+3, Sean Corfield wrote:
>>
>> For any library – for any function – there are always two classes of
>> unhappy path:
>>
>>
>>
>>1. Expected, known failure modes.
>>2. Unexpected, exceptional failure modes.
>>
>>
>>
>> The former should not use exceptions. The library/function should signal
>> the error in a documented way through its return value. Calling code should
>> check the return value to see if the library/function failed in one of the
>> expected, known, documented ways it is known to be possible to fail in, and
>> respond accordingly.
>>
>>
>>
>> The latter can (and should) use exceptions. An exception says “I got into
>> a state I can’t handle because I wasn’t expecting to get there!” and maybe
>> the caller can handle that and maybe it can’t. Library/function authors can
>> help callers here by:
>>
>>
>>
>>1. Providing a clear but succinct message for the exception,
>>2. And providing as much potentially useful detail in the ex-data as
>>possible.
>>
>>
>>
>> Does Java (and its standard library) overuse exceptions? Yes, absolutely.
>> It throws exceptions for all sorts of completely predictable failure modes.
>> We don’t need (or want) to be Java.
>>
>>
>>
>> Clojure provides perfectly good features to support both the expected and
>> the unexpected failure modes and, in particular, provides an excellent way
>> to convey information about the point of failure even when our code doesn’t
>> know how to recover.
>>
>>
>>
>> As Alex says, there may be value in providing a spec in your library for
>> the sort of ex-data you provide around exceptions. You’ll already be in
>> “regular Clojure land” as far as functions that return values that may
>> indicate success or expected, known failure modes.
>>
>>
>>
>> Sean Corfield -- (970) FOR-SEAN -- (904) 302-SEAN
>> An Architect's View -- http://corfield.org/
>>
>> "If you're not annoying somebody, you're not really alive."
>> -- Margaret Atwood
>>
>>
>> --
>> *From:* clo...@googlegroups.com  on behalf of
>> Oleksii Kachaiev 
>> *Sent:* Friday, October 26, 2018 2:28:35 PM
>> *To:* Clojure
>> *Subject:* Re: An Error spec?
>>
>> I've got the idea that you're not going to including anything like this
>> into core library. I just want to clarify because I'm actually a bit
>> confused here, and I think I'm not the only one. We promote
>> doing functional programming, staying declarative when possible, using data
>> with small pure testable functions as much as we can... and at the same
>> time declaring the "official" way of handling errors using exceptions,
>> which are side-effects by their nature, even tho' they play really poorly
>> with:
>>
>> * laziness (which is a default behavior for most operations with most
>> collections in the language)
>>
>> * multi-threaded code (especially in case of "opaque" jumps between
>> threads/executors when using core language concurrency primitives, or even
>> trying to emulate async event loop, i.e. with core.async)
>>
>> * macros (often macroexpand screws up the only feature we love about
>> exceptions: traces, making them pretty much useless)
>>
>> I thought that the design approach of using data and staying declarative
>> should also be applied to errors handling. And a contract declared for a
>> function should reflect not only "the happy path" but all potential cases.
>> We see a lot of languages put some mechanics into the core library or
>> language design (i.e. Scala, Rust, Haskell, Go etc) because errors and
>> errors handling is a very significant part of our programs that we just
>> cannot ignore. You can like or dislike them, you can always come up with
>> something very specific for your application or library. But the key idea
>> here is that core functionality is a rule of thumb for libraries &
>> ecosystem in general. So, when I do pick up library I can assume by default
>> the way error

Re: Atom/Clojure N00b - dependency issue

2018-07-28 Thread Benoît Fleury
Could it be the "funny" double quotes around your version number in the
project file?

On Sat, Jul 28, 2018 at 8:21 AM Nando Breiter  wrote:

> I've installed proto-repl as a package within Atom, and it works. I've
> never listed it as a dependency within a project.
>
>
>
> Aria Media Sagl
> +41 (0)76 303 4477 cell
> skype: ariamedia
>
> On Sat, Jul 28, 2018 at 1:38 PM, Bruce Hunter 
> wrote:
>
>> I have installed Atom and Clojure in order to learn the language, however
>> I am having a problem getting proto-repl to work. Here is the error message
>> I am getting:
>>
>> Could not find artifact repo.clojars.org:proto-repl:jar:�0.3.1� in
>> central (https://repo1.maven.org/maven2/)
>> Could not find artifact repo.clojars.org:proto-repl:jar:�0.3.1� in
>> clojars (https://repo.clojars.org/)
>>
>> According to some help I have found online, I need to add proto-repl to
>> the project dependencies. Understand that I am only just starting out in
>> the language, the advice wasn't very specific, so I am not sure I have got
>> this right. Here is my project.clj file:
>>
>> (defproject welcometoclojurebridge "0.1.0-SNAPSHOT"
>>   :description "Welcome to ClojureBridge InstallFest app"
>>   :license {:name "Eclipse Public License"
>> :url "http://www.eclipse.org/legal/epl-v10.html"}
>>   :dependencies [[org.clojure/clojure "1.8.0"]
>>  [quil "2.2.6"]
>>  [proto-repl “0.3.1”]])
>>
>> Does that look right? Atom is telling me it isn't right. Any help getting
>> up and running would be much appreciated! Sorry for the braindead n00b
>> question!
>>
>> Bruce.
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OK idea to replace conj and cons with "prepend" and "append" macros that have consistent behavior and return same types as args?

2018-07-19 Thread Benoît Fleury
Sorry if if it was not clear. I was not asking for more documentation. I
understand that the documentation of `conj` should not say anything about
how the different implementations work since it is only about adding an
element to a collection in constant time. And you can always have future
implementations of the operation that will behave differently. So the conj
function has the right documentation in my opinion. It describes its
semantic.

My question is about having implementations "extend" the semantic of conj.
By extending the semantic I mean that it allows the user to have more
expectations about the behavior of the operation. If we use conj on a
vector, we expect the element to be added at the end. Our programs rely on
this property. In this sense, we extend the semantic of conj in my opinion.
With operations like prepend/append, the semantic is in a way complete. The
different sorted collection implementations will always behave the same
when prepending or appending an element (except for the time complexity of
course :)). I'm trying to find other examples in Clojure and other
programming languages where implementations of an abstraction extend the
semantic of the abstraction.

And to be completely clear, I'm not complaining about the design decision
in Clojure. I'm just trying to really understand what the design is, what
are the trade-offs and where the confusion might come from.







On Thu, Jul 19, 2018 at 4:18 PM Andy Fingerhut 
wrote:

>
>
> On Thu, Jul 19, 2018 at 1:04 PM Benoît Fleury  wrote:
>
>> Replying to myself ... :)
>>
>> 1. Am I wrong in thinking that most Clojure programmers use append/prepend
>> as mental models for the different implementations of conj?
>>
>> No.
>>
>> 2. Am I wrong in thinking that they shouldn't?
>>
>> Yes.
>>
>> Clojure developers need to know the behavior of conj for vectors and
>> lists. This is even what often drives the choice between the two data
>> structures.
>>
>> And I think that's where a lot of confusion comes from. I think I
>> (and maybe others) expect that the complete semantic of a function
>>  be described in its documentation. I don't know whether this
>>  expectation is justified or not :)
>>
>
> You are not alone in wishing for more details in documentation of Clojure
> functions.  That is one of the reasons ClojureDocs.org exists, for example,
> and its first few examples make explicit the different behavior of conj for
> lists vs. vectors: http://clojuredocs.org/clojure.core/conj
>
> If you wish for the Clojure core team to provide that style of
> documentation for you, I expect your wish will not be fulfilled.  It is not
> technically difficult to replace all Clojure doc strings with more verbose
> variants.  It _is_ a lot of work to write documentation like that and
> maintain it over time.  For example, here is a whole bunch of stuff I wrote
> on the behavior of clojure.core/= and clojure.core/hash.  It took way more
> hours than I care to admit:
> https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/equality.md
>
> I believe someone wrote a book aiming to be a reference to all Clojure
> functions, but don't recall the name or author at the moment, nor have I
> read it.
>
> Andy
>
>
>
>>
>>
>> On Thu, Jul 19, 2018 at 11:04 AM Benoît Fleury  wrote:
>>
>>> I agree with Alex. It is important to understand the rationale behind the
>>> behavior of conj. conj is for adding an element to a collection. It
>>> doesn't
>>> say anything about ordering. It has been chosen as an operation, as
>>> opposed to append/prepend, because it can be implemented with the
>>> same time complexity for a lot of data structures.
>>>
>>> To convince myself that time complexity mattered in programming, I take
>>> the example of a stack. If you give me an implementation of a stack that
>>> push and pop items in linear time, I will write very inefficient
>>> programs
>>> very quickly. To the point of not working at all. So it makes sense to
>>> me
>>> that space/time complexity should be part of the signature of an
>>> operation.
>>>
>>> Now, I think the problem here comes from the fact that we have a tendency
>>> to infer the semantic of an operation from its behavior on certain
>>> types. We
>>> see that (conj [1 2] 3) returns [1 2 3] so we conclude that conj is for
>>> adding
>>> an item at the end of a collection. And then we get surprised when the
>>> behavior is "different" for other types. As Clojure programmers, it is
>>> something
>>> we ne

Re: OK idea to replace conj and cons with "prepend" and "append" macros that have consistent behavior and return same types as args?

2018-07-19 Thread Benoît Fleury
Replying to myself ... :)

1. Am I wrong in thinking that most Clojure programmers use append/prepend
as mental models for the different implementations of conj?

No.

2. Am I wrong in thinking that they shouldn't?

Yes.

Clojure developers need to know the behavior of conj for vectors and
lists. This is even what often drives the choice between the two data
structures.

And I think that's where a lot of confusion comes from. I think I
(and maybe others) expect that the complete semantic of a function
 be described in its documentation. I don't know whether this
 expectation is justified or not :)


On Thu, Jul 19, 2018 at 11:04 AM Benoît Fleury  wrote:

> I agree with Alex. It is important to understand the rationale behind the
> behavior of conj. conj is for adding an element to a collection. It doesn't
> say anything about ordering. It has been chosen as an operation, as
> opposed to append/prepend, because it can be implemented with the
> same time complexity for a lot of data structures.
>
> To convince myself that time complexity mattered in programming, I take
> the example of a stack. If you give me an implementation of a stack that
> push and pop items in linear time, I will write very inefficient programs
> very quickly. To the point of not working at all. So it makes sense to me
> that space/time complexity should be part of the signature of an operation.
>
> Now, I think the problem here comes from the fact that we have a tendency
> to infer the semantic of an operation from its behavior on certain types.
> We
> see that (conj [1 2] 3) returns [1 2 3] so we conclude that conj is for
> adding
> an item at the end of a collection. And then we get surprised when the
> behavior is "different" for other types. As Clojure programmers, it is
> something
> we need to be careful about and make sure we understand the actual
> semantic of the operations.
>
> However, I think it is easier said than done. I would be ready to bet that
> a
> lot of Clojure programs rely on the fact that conj *appends* to a vector or
> *prepends* to a list. I agree that it is problematic. First, it makes the
> understanding of the code harder because you need to remember the behavior
> of conj on each type. And it prevents the implementation of conj to change
> because so many programs rely on implementation details. But to all expert
> Clojure programmers here, can you honestly think about what mental model
> you
> use when using conj on vectors and lists? Are you really thinking: I'm
> adding
> this element to this collection. I don't really care where it ends up :) ?
>
> So my questions are:
>
> 1. Am I wrong in thinking that most Clojure programmers use append/prepend
> as mental models for the different implementations of conj?
>
> 2. Am I wrong in thinking that they shouldn't?
>
> 3. And if I'm not wrong, how could we make it easier for programmers to
> make
> sure they code against the semantic of an operation and not its
> implementation
> details? Is there methods, tools or tests that could help us with that?
>
>
> On Thu, Jul 19, 2018 at 3:20 AM Didier  wrote:
>
>> Hey Alan,
>>
>> Nice job on Tupelo by the way. I do find it a bit bloated though, and
>> that's why I never use it. Any reason why all the different namespace are
>> still mixed together? Seem like they could each be an independent lib, like
>> how the datomic namespace was split out.
>>
>> On Wednesday, 18 July 2018 13:16:15 UTC-7, Alan Thompson wrote:
>>>
>>> There is also a function `glue`
>>> <https://github.com/cloojure/tupelo#gluing-together-like-collections>
>>> for combining like collections:
>>>
>>>
>>> -
>>> Gluing Together Like Collections
>>>
>>> The concat function can sometimes have rather surprising results:
>>>
>>> (concat {:a 1} {:b 2} {:c 3} );=>   ( [:a 1] [:b 2] [:c 3] )
>>>
>>> In this example, the user probably meant to merge the 3 maps into one.
>>> Instead, the three maps were mysteriously converted into length-2 vectors,
>>> which were then nested inside another sequence.
>>>
>>> The conj function can also surprise the user:
>>>
>>> (conj [1 2] [3 4] );=>   [1 2  [3 4] ]
>>>
>>> Here the user probably wanted to get [1 2 3 4] back, but instead got a
>>> nested vector by mistake.
>>>
>>> Instead of having to wonder if the items to be combined will be merged,
>>> nested, or converted into another data type, we provide the glue function
>>> to *alway

Re: OK idea to replace conj and cons with "prepend" and "append" macros that have consistent behavior and return same types as args?

2018-07-19 Thread Benoît Fleury
I agree with Alex. It is important to understand the rationale behind the
behavior of conj. conj is for adding an element to a collection. It doesn't
say anything about ordering. It has been chosen as an operation, as
opposed to append/prepend, because it can be implemented with the
same time complexity for a lot of data structures.

To convince myself that time complexity mattered in programming, I take
the example of a stack. If you give me an implementation of a stack that
push and pop items in linear time, I will write very inefficient programs
very quickly. To the point of not working at all. So it makes sense to me
that space/time complexity should be part of the signature of an operation.

Now, I think the problem here comes from the fact that we have a tendency
to infer the semantic of an operation from its behavior on certain types. We
see that (conj [1 2] 3) returns [1 2 3] so we conclude that conj is for
adding
an item at the end of a collection. And then we get surprised when the
behavior is "different" for other types. As Clojure programmers, it is
something
we need to be careful about and make sure we understand the actual
semantic of the operations.

However, I think it is easier said than done. I would be ready to bet that a
lot of Clojure programs rely on the fact that conj *appends* to a vector or
*prepends* to a list. I agree that it is problematic. First, it makes the
understanding of the code harder because you need to remember the behavior
of conj on each type. And it prevents the implementation of conj to change
because so many programs rely on implementation details. But to all expert
Clojure programmers here, can you honestly think about what mental model you
use when using conj on vectors and lists? Are you really thinking: I'm
adding
this element to this collection. I don't really care where it ends up :) ?

So my questions are:

1. Am I wrong in thinking that most Clojure programmers use append/prepend
as mental models for the different implementations of conj?

2. Am I wrong in thinking that they shouldn't?

3. And if I'm not wrong, how could we make it easier for programmers to make
sure they code against the semantic of an operation and not its
implementation
details? Is there methods, tools or tests that could help us with that?


On Thu, Jul 19, 2018 at 3:20 AM Didier  wrote:

> Hey Alan,
>
> Nice job on Tupelo by the way. I do find it a bit bloated though, and
> that's why I never use it. Any reason why all the different namespace are
> still mixed together? Seem like they could each be an independent lib, like
> how the datomic namespace was split out.
>
> On Wednesday, 18 July 2018 13:16:15 UTC-7, Alan Thompson wrote:
>>
>> There is also a function `glue`
>> 
>> for combining like collections:
>>
>>
>> -
>> Gluing Together Like Collections
>>
>> The concat function can sometimes have rather surprising results:
>>
>> (concat {:a 1} {:b 2} {:c 3} );=>   ( [:a 1] [:b 2] [:c 3] )
>>
>> In this example, the user probably meant to merge the 3 maps into one.
>> Instead, the three maps were mysteriously converted into length-2 vectors,
>> which were then nested inside another sequence.
>>
>> The conj function can also surprise the user:
>>
>> (conj [1 2] [3 4] );=>   [1 2  [3 4] ]
>>
>> Here the user probably wanted to get [1 2 3 4] back, but instead got a
>> nested vector by mistake.
>>
>> Instead of having to wonder if the items to be combined will be merged,
>> nested, or converted into another data type, we provide the glue function
>> to *always* combine like collections together into a result collection
>> of the same type:
>>
>> ; Glue together like collections:
>> (is (= (glue [ 1 2] '(3 4) [ 5 6] )   [ 1 2 3 4 5 6 ]  ))   ; all 
>> sequential (vectors & lists)
>> (is (= (glue {:a 1} {:b 2} {:c 3} )   {:a 1 :c 3 :b 2} ))   ; all maps
>> (is (= (glue #{1 2} #{3 4} #{6 5} )  #{ 1 2 6 5 3 4 }  ))   ; all sets
>> (is (= (glue "I" " like " \a " nap!" )   "I like a nap!"   ))   ; all text 
>> (strings & chars)
>> ; If you want to convert to a sorted set or map, just put an empty one first:
>> (is (= (glue (sorted-map) {:a 1} {:b 2} {:c 3})   {:a 1 :b 2 :c 3} ))
>> (is (= (glue (sorted-set) #{1 2} #{3 4} #{6 5})  #{ 1 2 3 4 5 6  } ))
>>
>> An Exception will be thrown if the collections to be 'glued' are not all
>> of the same type. The allowable input types are:
>>
>>-
>>
>>all sequential: any mix of lists & vectors (vector result)
>>-
>>
>>all maps (sorted or not)
>>-
>>
>>all sets (sorted or not)
>>-
>>
>>all text: any mix of strings & characters (string result)
>>
>>
>>
>> On Wed, Jul 18, 2018 at 1:13 PM, Alan Thompson  wrote:
>>
>>> As someone mentioned, the functions `prepend` and `append` exist in the
>>> Tupelo library
>>> 

Re: Why does the `def-` not exist?

2018-02-28 Thread Benoît Fleury
Hi Leon,

as Alex said above, if you really need something I would recommend adding
it in a library. I'm sure you will encounter more scenarios in the future
where you need things that are not in the core language. You can put them
in the same library. I don't think anyone will (or should) blame you for
doing this.

As for beginners encountering this def- issue, maybe it is a good
opportunity to talk to them about Lisp being a programmable programming
language. That's one of the big advantages of Lisp. It would be unfortunate
to restrict ourselves to a way of thinking inherited from inferior
languages.

It shouldn't be a lot of work. A quick copy-and-paste from `defn-` gave me
this:

(defmacro def-
  "same as def, yielding non-public def"
  [name & decls]
(list* `def (with-meta name (assoc (meta name) :private true)) decls))

On Wed, Feb 28, 2018 at 1:58 PM, Leon Grapenthin 
wrote:

> The one issue with the lack of def- is the existence of defn-. If defn-
> didn't exist, no one would ask for def-. I believe this is where the
> "regret" comes from.
> The other issue with the lack of def- is that its annoying to type
> ^:prviate. I don't see how you could accidentally mistype it (never
> happened IME) or the need for compiler aid.
> If beginners think that there is a magic postfix syntax, I don't see how
> this is a problem. They are beginners and naturally there will be many
> things that fail their intuition.
> Compiler auto injection on postfix magic I'm strongly opposed to.
>
> @Alex thanks for your long reply yesterday and the statistics! I'll get
> back to that.
>
>
> On Wednesday, February 28, 2018 at 8:06:51 PM UTC+1, Didier wrote:
>>
>> I think the issue is not with the lack of def-, but with the use of
>> metadata for private, as well as the presence of defn-.
>>
>> Becauae defn- exists, most newcomers think that postfix - on var defining
>> special forms, macros and fns is how you mark things as private.
>>
>> But its not, defn- is a syntactic hack.
>>
>> The compiler and runtime looks for the private metadata on the Var for
>> that. But metadata is easy to typo and always confusing as to where it
>> needs to be inserted.
>>
>> Not sure there's a solution. Maybe reserved meta could be turned into a
>> different syntax of reserved keywords which the compiler could validate if
>> its misplaced or mistyped? Or postfix - on any first symbol in a form could
>> be special syntax where the compiler auto-injects the private meta on the
>> returned Var.
>>
>> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.