Re: Modelling in Clojure
James Reeves ja...@booleanknot.com writes: On 17 October 2014 16:21, Phillip Lord phillip.l...@newcastle.ac.uk wrote: http://en.wikipedia.org/wiki/Uniform_access_principle To my knowledge, Clojure cannot do this. Yes, Clojure pretty much rejects the idea of uniform access. I don't think it does. I think it just does not support it which is a somewhat different thing. With regard to automatically :doc string, why can't you set it when the var is created? Two reasons. The first is specific to my library, which is that the var contains a mutable Java object. So the :doc string may change over time, independently of the value of the var. Don't use mutable objects would be an obvious response, but not a useful one in this case. If you're placing mutable objects in a top-level var, and having that var's docstring change based on their contents, that's a strong indication you're doing something wrong. Yes, this is certainly a possibility. It sounds like you're trying to interoperate with a Java library that's very structured around OOP principles, and very hard to translate into idiomatic Clojure. My guess is that you wouldn't have the issues you mention in a pure Clojure solution. Which is the actuality. While using mutable objects and global state may be an indication that I am doing something wrong, my belief is that starting a software project by ignoring existing java libraries and rewriting everything in Clojure is a much bigger error. I got to a usable piece of software in two months; this would not have happened from scratch. Still, although my example might appear irrelevant to Clojure in general, I don't think it is. Clojure's current docstring support is not very good (and there was a thread here about it not long ago). It would be nice to have something richer. For really rich documentation, maintaining the docstrings is a different file might make sense. Clojure can support this at the moment, but only in the way that I have -- the var metadata could be updated at load time. What it cannot do (easily) is support lazy loading of the file documentation at the point of first use, because the decision was made originally that :doc metadata is a value and is NOT computed. Phil -- 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: Modelling in Clojure
Fluid Dynamics a2093...@trbvm.com writes: I don't know who is the outlier. The point is that Scala, for instance, has explicit support to hide the distinction between accessing a value and computing a value. The point is to support the uniform access principle. http://en.wikipedia.org/wiki/Uniform_access_principle To my knowledge, Clojure cannot do this. It seems to me that some support could be created for this. Specifically, we'd want to make it that a) (deref foo) on a non-IDeref just evaluates to foo in a no-op, and furthermore that if foo is known at compile time not to be an IDeref the (deref foo) compiles away to just foo, so has no runtime cost; and b) (deref (delay (some-fcall))) amounts to (force (delay (some-fcall))) and where the compiler knows the thing being derefed is a delay (via type hint or whatever) is as efficient as just (some-fcall) at run-time the first time called, and as efficient as ((constantly foo)) for some value of foo thereafter. In that case, one could hide the computed-or-not nature of some data behind expecting users to use @my-thing to access it, and if my-thing is not an IDeref it is the same as my-thing, but it can be changed later to a delay to make it a lazily-computed thing without breaking the API, and without much runtime efficiency cost, given that the new object is hinted with ^IDeref or something. It's definately supportable. Symbol macros could also achieve the same thing; Clojure has these, but not globally. Phil -- 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: Modelling in Clojure
James Reeves ja...@booleanknot.com writes: On 18 October 2014 08:28, Mark Engelberg mark.engelb...@gmail.com wrote: Yeah, it's hard to deny the convenience of Clojure's keyword lookups and standard assoc mechanism for getting and setting stored values, but I think Bertrand Meyer's Uniform Access Principle reflects some pretty deep thinking about the kinds of complications that arise in maintaining large programs. Although the Clojure community mostly rejects the Uniform Access Principle right now, as people start writing larger programs in Clojure, and need to maintain them for longer periods of time, it will be interesting to see if the pendulum swings back in favor of uniform access. You make it sound as if structuring an application around data, rather than APIs, is untested at scale. I'd argue the opposite: the only architecture we know works at scale is data driven. The largest systems we've developed, including the web itself, are data driven. Interesting. So, if you resolve http://www.clojure.org, is this data or is it computed? I don't think you can tell. The web supports the Uniform Access Principle. Phil -- 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: Modelling in Clojure
On Monday, 20 October 2014, Phillip Lord phillip.l...@newcastle.ac.uk wrote: Interesting. So, if you resolve http://www.clojure.org, is this data or is it computed? You're dereferencing a ref (url) to get an immutable value (string). Maybe it would be worth exploring ways to implement IDeref with custom data types? -- 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: Modelling in Clojure
On 20 October 2014 12:23, Phillip Lord phillip.l...@newcastle.ac.uk wrote: James Reeves ja...@booleanknot.com writes: Yes, Clojure pretty much rejects the idea of uniform access. I don't think it does. I think it just does not support it which is a somewhat different thing. I thought it was pretty clear that Clojure prefers data over APIs. The uniform access principle is about preferring APIs over data, which seems counter to Clojure's ideology. Still, although my example might appear irrelevant to Clojure in general, I don't think it is. Clojure's current docstring support is not very good (and there was a thread here about it not long ago). It would be nice to have something richer. For really rich documentation, maintaining the docstrings is a different file might make sense. Clojure can support this at the moment, but only in the way that I have -- the var metadata could be updated at load time. What it cannot do (easily) is support lazy loading of the file documentation at the point of first use, because the decision was made originally that :doc metadata is a value and is NOT computed. There's no reason why you have to use the :doc metadata for that. Just write another function that takes a var and spits out some documentation. On 20 October 2014 12:26, Phillip Lord phillip.l...@newcastle.ac.uk wrote: The largest systems we've developed, including the web itself, are data driven. Interesting. So, if you resolve http://www.clojure.org, is this data or is it computed? I don't think you can tell. The web supports the Uniform Access Principle. The response may be computed, but once it's sent to the client it's immutable data. The response returned has no inherent API associated with it. To put it another way, consider the function: (defn build-user [first-name last-name] {:first-name first-name :last-name last-name :full-name (str first-name last-name)}) Like a website, a function may perform computations, but its return value is immutable data. Would you say the above conforms the the Uniform Access Principle? - James -- 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: Modelling in Clojure
James Reeves ja...@booleanknot.com writes: Yes, Clojure pretty much rejects the idea of uniform access. I don't think it does. I think it just does not support it which is a somewhat different thing. I thought it was pretty clear that Clojure prefers data over APIs. The uniform access principle is about preferring APIs over data, which seems counter to Clojure's ideology. The uniform access principle is about having uniform access to data and APIs. It's not about prefering one or the other. Still, although my example might appear irrelevant to Clojure in general, I don't think it is. Clojure's current docstring support is not very good (and there was a thread here about it not long ago). It would be nice to have something richer. For really rich documentation, maintaining the docstrings is a different file might make sense. Clojure can support this at the moment, but only in the way that I have -- the var metadata could be updated at load time. What it cannot do (easily) is support lazy loading of the file documentation at the point of first use, because the decision was made originally that :doc metadata is a value and is NOT computed. There's no reason why you have to use the :doc metadata for that. Just write another function that takes a var and spits out some documentation. Yes, which is what I have done, of course. Now it won't work in any IDE which looks for the docstring as :doc metadata. It is totally unextensible. I do not think that this is good. The largest systems we've developed, including the web itself, are data driven. Interesting. So, if you resolve http://www.clojure.org, is this data or is it computed? I don't think you can tell. The web supports the Uniform Access Principle. The response may be computed, but once it's sent to the client it's immutable data. Well, that's the point, you cannot tell. So, for example, I can provide a website implemented over a relational database. Or I can serialize it out as static files. Or I can add a caching layer which serializes lazily, and redoes every hour. The response returned has no inherent API associated with it. That sort of depends on the response. To put it another way, consider the function: (defn build-user [first-name last-name] {:first-name first-name :last-name last-name :full-name (str first-name last-name)}) Like a website, a function may perform computations, but its return value is immutable data. Would you say the above conforms the the Uniform Access Principle? As I said at the beginning, it is possible to achieve UAP by making *everything* a function. So, we can automatically achieve UAP by ONLY using functions and never values. So consider for example, this case. (:doc (meta #'concat)) The return value of this expression can never be computed (short of reimplementing ILookup or IMeta which, of course, we could do). On the other hand ((:doc (meta #'concat))) could be computed or not, since the function returned could just be returning a value. So, the latter supports the UAP, the former doesn't. In fact, this is how I squared the circle in my case. I changed data-factory to (data-factory) In most cases the data-factory function just returns a constant value, but it can use computation when I choose. Phil -- 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.
[ANN] New release 0.29.0 of Counterclockwise
Counterclockwise, the Eclipse Clojure development tool. Counterclockwise 0.29.0 has been released. Improvement over 0.28.1 based on user feedback. Also, upgraded Leiningen version to 2.5.0. ChangeLog = http://doc.ccw-ide.org/ChangeLog.html#_changes_between_counterclockwise_0_28_1_and_0_29_0 Installation instructions == http://doc.ccw-ide.org/documentation.html#_install_counterclockwise Cheers, -- Laurent Petit -- 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: Modelling in Clojure
On 20 October 2014 14:02, Phillip Lord phillip.l...@newcastle.ac.uk wrote: The uniform access principle is about having uniform access to data and APIs. It's not about prefering one or the other. Right, but Clojure *does* heavily prefer data over APIs, and therein lies the conflict. Yes, which is what I have done, of course. Now it won't work in any IDE which looks for the docstring as :doc metadata. It is totally unextensible. I do not think that this is good. Clojure prefers simple solutions over easy solutions. Unrestricted polymorphism and universal access would make solving this problem easier, but they also create more complexity. Or to put it another way, rather than trying to shoehorn a solution into a system that wasn't built for it, we should design a new system around the desired solution. In the case of documentation, the most obvious approach is to decide on a new protocol all IDEs can implement. The response may be computed, but once it's sent to the client it's immutable data. Well, that's the point, you cannot tell. So, for example, I can provide a website implemented over a relational database. Or I can serialize it out as static files. Or I can add a caching layer which serializes lazily, and redoes every hour. Yes, and so can a function. Clojure doesn't say, you shouldn't compute, it says, you should separate computations and data. I suppose it's possible to build a service where every value lookup requires hitting an external server, but no-one sane builds a web service like that. Latency concerns alone mean that data and computation need to be separated in distributed systems. The response returned has no inherent API associated with it. That sort of depends on the response. I suppose one could design architecture around passing around executable code that's executed in a sandbox by the client, but see my previous point about sane design. To put it another way, consider the function: (defn build-user [first-name last-name] {:first-name first-name :last-name last-name :full-name (str first-name last-name)}) Like a website, a function may perform computations, but its return value is immutable data. Would you say the above conforms the the Uniform Access Principle? As I said at the beginning, it is possible to achieve UAP by making *everything* a function. So, we can automatically achieve UAP by ONLY using functions and never values. The point I was trying to make was that computed values (such as those produced by a web server) do not necessarily imply UAP. I don't disagree that UAP has some benefits, but it comes with a huge number of tradeoffs. Given that the problem it tries to solve is, in my experience at least, exceeding rare, it really doesn't seem worth the additional complexity. - James -- 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: Modelling in Clojure
James Reeves ja...@booleanknot.com writes: Yes, which is what I have done, of course. Now it won't work in any IDE which looks for the docstring as :doc metadata. It is totally unextensible. I do not think that this is good. Clojure prefers simple solutions over easy solutions. A nice aphorism sometimes, but content free in this case, I think. Unrestricted polymorphism and universal access would make solving this problem easier, but they also create more complexity. Or to put it another way, rather than trying to shoehorn a solution into a system that wasn't built for it, we should design a new system around the desired solution. So, there is this tourist, and he asks a local, how do I get into town. Hmmm, says the local, if I want to get into town, I wouldn't start from here. Software engineering is a compromise, and designing a new system is a pain, especially if multiple people have to update to it. I think Clojure's doc string support is weak. Part of the reason for this, is because it is not extensible. The main reason that it is not extensible is that, in Clojure, once you have decided that something is a value, you are stuck. Don't care about my use-case? That's fine. Have a look at Andy Fingerhuts thalia which helps to fix Clojure's poor documentation. https://github.com/jafingerhut/thalia Same problem -- all has to be done up front, which is ugly and nasty. As a result, I don't use thalia, which is a shame. The response may be computed, but once it's sent to the client it's immutable data. Well, that's the point, you cannot tell. So, for example, I can provide a website implemented over a relational database. Or I can serialize it out as static files. Or I can add a caching layer which serializes lazily, and redoes every hour. Yes, and so can a function. Clojure doesn't say, you shouldn't compute, it says, you should separate computations and data. Which is nice and simple, yes. And has negative consequences in terms of extensibility. I understand if you are happy with this compromise. But it is a compromise. The point I was trying to make was that computed values (such as those produced by a web server) do not necessarily imply UAP. I don't disagree that UAP has some benefits, but it comes with a huge number of tradeoffs. Given that the problem it tries to solve is, in my experience at least, exceeding rare, it really doesn't seem worth the additional complexity. Well, the question is, where does this additional complexity come from. In Java, it results in enormous quantities of boilerplate get/set methods. In Scala, these are autocoded away. In Clojure, I don't see an easy solution. Not going to stop me using the language, but it's a weak spot. Phil -- 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: Modelling in Clojure
Well, the question is, where does this additional complexity come from. In Java, it results in enormous quantities of boilerplate get/set methods. In Scala, these are autocoded away. Boilerplate isn't complexity: It's inefficiency. I'll grant that it creates complexity-potential-energy via many increased space for complexity to hide. However, it's far more complex to eliminate boilerplate via dynamic mechanisms, such as interface dispatch or, heaven forbid, Ruby-style abuses such as method_missing. Simpler is to eliminate boilerplate by developing terser encodings in terms of values, and bringing computation to bear to interpret (or translate) those values. But I'll argue that avoiding the UAP isn't about complexity. It's about an intentional modeling of non-uniform access. Clojure data is built, constructively, out of lists, maps, sets, vectors, symbols, keywords, numbers, strings, etc. Any inductive data types, by the very nature of computation, are implemented in terms of co-inductive operations on codata types. You can't observe something in your computer without executing code to interpret some representation which models some abstraction. Any representation is built concretely out of the abstractions below it. By committing to :keyword style access, you're making a proclamation that you're operating on a concrete representation. If that concrete representation happens to be implemented abstractly (as it must be), you can override it (again with ILookup, etc). However, if you're going to override it, you damn well better provide value-like semantics. UAP grants you flexibility in changing an abstraction. However, it grants *too much* flexibility. It lets you change from a convincing emulation of a true mathematical value to a full-blown computation object. Making operations on data source-incompatible with operations on codata is a feature, not a bug. -- 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: Modelling in Clojure
On 20 October 2014 17:08, Phillip Lord phillip.l...@newcastle.ac.uk wrote: James Reeves ja...@booleanknot.com writes: Clojure prefers simple solutions over easy solutions. A nice aphorism sometimes, but content free in this case, I think. Well, no... The whole point is that simple and easy in this context have objective definitions. If you go by Rich's definition of simple, then a value is *objectively* simpler than a function. So, there is this tourist, and he asks a local, how do I get into town. Hmmm, says the local, if I want to get into town, I wouldn't start from here. That makes perfect sense, *if* the tourist is making the trip *only once*. But that hardly applies in this case, because a documentation system will be used many times. So there's this business owner, and he asks a local, What's the quickest route for my vehicles to get to town? The local considers, and replies, You'd be able to get into town much faster if your vehicles were stationed on the other side of town. A small context shift, and suddenly the local's advice is extremely useful. Which is nice and simple, yes. And has negative consequences in terms of extensibility. I understand if you are happy with this compromise. But it is a compromise. I don't disagree, but I do consider the compromise to be a minor one. UAP has huge disadvantages in terms of complexity, repetition, scalability, reliability, isolation, and a whole bunch of other things that Clojure is explicitly trying to avoid. On the other hand, I can't personally recall a situation where it would have actually been useful to me. Well, the question is, where does this additional complexity come from. In Java, it results in enormous quantities of boilerplate get/set methods. In Scala, these are autocoded away. By complexity I'm again referring to Rich's more objective definition of the term. Complexity in this sense is a measurement of how many things can affect part of your program. An immutable value is the simple, because nothing can affect it. A pure function is more complex, because it's affected by its arguments, and a side-effectful function has even an greater complexity, because it can be affected by pretty much anything. The simple vs. easy idea is a short way of saying we should prioritise reducing coupling between components (simplicity), even at the cost of short term gains (easiness). - James -- 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: [ANN] New release 0.29.0 of Counterclockwise
Working great for me - thanks Laurent! On Monday, 20 October 2014 21:22:31 UTC+8, Laurent PETIT wrote: Counterclockwise, the Eclipse Clojure development tool. Counterclockwise 0.29.0 has been released. Improvement over 0.28.1 based on user feedback. Also, upgraded Leiningen version to 2.5.0. ChangeLog = http://doc.ccw-ide.org/ChangeLog.html#_changes_between_counterclockwise_0_28_1_and_0_29_0 Installation instructions == http://doc.ccw-ide.org/documentation.html#_install_counterclockwise Cheers, -- Laurent Petit -- 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.