Re: [?] Adding my own function to clojure.core namespace
You might also have a look at a library called vinyasa > https://github.com/ardumont/vinyasa > You can can add it to your lein profile to copy functions into clojure.core and prefix them. The prefix makes it very clear that these are not part of standard clojure.core. (inject 'clojure.core '>> '[[clojure.repl doc [source source]]]) ;; => will create the var #'clojure.core/>>doc and #'clojure.core/source -- 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] Git Deps for Clojure!
> > > > >> I’d really like a dependency system that makes each dep’s transitive >> dependencies only visible to itself, so there would never be any reason to >> resolve dependencies. >> > > You need classloader support for this and indeed this is what OSGi and > some early versions of the Java module system do. Working in that kind of > environment is very constraining. A lot of discipline is required with > respect to your interfaces between loaders and in general I think it's way > too much of a burden to use as the normal operating mode (which is one > reason you don't see it in the Java module system of java 9). It is a good > option for systems where you want users to plug in functionality and the > scope of those interface points is small and highly controlled. > I have run into incompatible transitive dependencies a lot throughout my career. In many cases its not that big a deal but for cross cutting libraries such as data serialization etc it can be hard to get all of your dependencies to agree on a common version. Here is a concrete example I ran into just today: https://github.com/thheller/shadow-cljs/issues/177 and the library that caused the issue is non-other than core.async! I second the idea of private dependencies. I have had the displeasure of working with OSGI and I think the reason its complex is not so much because the required metadata is hard to figure out... the complexity mostly comes from the starting, stopping and restarting bundles within a running jvm in non deterministic order. Another issue is that the dependency metadata needs to be included within each jar and since most library authors don't see the value of OSGI they don't provide it to users to rebundle the jar with the required metatata. This problem is similar to that of cljsjs, most javascript devs do not see any value in any significant value is using closure compile over uglyify (myself included as externs are a pain to maintain, minified stacktraces are useless, and errors are subtle and hard to debug), but the clojurescript community does see value in this so they do their best to maintain this metadata even if it means rebuilding projects. So what is the alternatives: 1. Don't upgrade (common solution when there are breaking changes) 2. Try to get upstream maintainer to upgrade (most common when changes are not breaking and/or maintainer willing to do the work) 3. Fork the upstream project and maintain your own release using the desired version 4. Split your app into multiple pieces so they can run in different JVM instances (enter the microservice) I think the idea that everything can use the same version is oversimplified and creating microservice shouldn't be necessary just because you can't get all your dependencies to agree. -- 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: Doseq, map-style
On Jun 18, 2012, at 2:09 AM, Christophe Grand christo...@cgrand.net wrote: On Sun, Jun 17, 2012 at 8:59 PM, Kurt Harriger kurtharri...@gmail.comwrote: Data structure is an implementation detail... It's not. Not in clojure. It is in OO, but clojure is not an OO language, so it's not an implementation detail in clojure. That is my point, representations SHOULD be considered implementation details, because representations change... if you treat them as contracts your code will break everywhere, if you wrap them with abstractions your code will only need to change in one place... Representations are values in Clojure, they are not mixed with behaviors like in mainstream OO. It follows that, if your representation need to change, you can write a converter function (or two if you want to convert from and to the old representation), that's easy, easier than writing an adapter class in Java because the adapter class must implement new behaviors on top of old ones (or the other way round). Isnt that just creating an api? Everywhere the old model exists you need to call a function to create the desired data structure and this adds another layer of complexity that needs maintained. Not all conversions are straight forward, may require additional context of whatever introducing the need for deferred computation. Christophe -- 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 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
Re: Doseq, map-style
I did not know about lazy map either… This might be exactly what I was needed. Maps with referentially transparent properties rather than fields. A way to make minor changes to map representation without adding an api in advance, introducing breaking changes, redundant properties, or converters and still work with the clojure core apis. This might make the simple refactoring a bit easier. On Monday, June 18, 2012 8:48:37 AM UTC-6, Vinzent wrote: Yeah, I'm waiting for concrete example too. By the way, if you really need to change :area from value to deferred computation then you can just change your data structure implementation from hash-map to lazy map (i.e. a map whose values are delays deref'd on access). This would require changing code only in one place. -- 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
Re: Doseq, map-style
On Monday, June 18, 2012 8:01:47 AM UTC-6, tbc++ wrote: Isnt that just creating an api? Everywhere the old model exists you need to call a function to create the desired data structure and this adds another layer of complexity that needs maintained. Not all conversions are straight forward, may require additional context of whatever introducing the need for deferred computation. Can you provide a concrete example (with code perhaps)? I guess I'm not seeing where the problems arise. In this situation I normally either, 1) create a new fetch function to create a new map of data in the new format 2) provide duplicate data in the map that's computed differently, 3) update the old code to the new map. Here at work we have a 20 year old application that is almost 100% backwards compatible (the server can talk to much older clients). And it does so by using pure data. The server has setup contracts saying this is what Project data looks like, this is what Company Data looks like and those contracts never change. The 3D Software Blender (blender.org) operates on this same principle. After almost a decade, their latest software can open 1.0 .blend files, and vice versa. All these applications work off of unchanging data contracts. So I'm interested in seeing concrete examples of how your application differs. Its not the external contracts that are changing but the internal contracts between namespaces... as I add features I add new requirements clarify my understanding and decide to replace them with new ones. I wish I could say just don't change them, but the internal contracts are implementation details no one uses them but me. If I decide to change them stuff breaks and that would be true in OO too, but in I know how to go about these refactorings incrementally in OO until the old abstractions fall away and become dead code, in clojure new abstractions mean lots of breaking changes and nothing works until everything works. I wouldn't mind sitting down with someone in the Denver area and getting some feedback on my code, eventually I would like to open source the code but I don't expect that to happen anytime in the near future. Timothy -- 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
Re: Doseq, map-style
On Jun 18, 2012, at 5:35 PM, Softaddicts lprefonta...@softaddicts.ca wrote: Lets talk a bit about my world here. We created a product to link medical equipments using a variety of protocols, some talk HL7, DICOM, others have proprietary means to access data from various places. From the start we chose the richest data representation, some of it came from a few medical standards and another part is our own creation to carry stuff that is outside the scope of the business field (non medical data). We did not define specific records, instead we factored out the protocol definition (the contract) from the representation(s) and created its definition using persistent data structures and Clojure protocols The profile is being augmented often, new fields are added to keep up with support of new devices, new standards,... We never remove stuff from protocol definitions and we always aim to generate fully populated messages from the data available at a specific end point. It's all data (above 10k lines for as profile using our custom DSL) and less than 500 lines of code to define and handle. We have three message representations more or less equivalent, one is string based (HL7-enabled devices accept this representation), another one is for serialization and the last one is a full representation with each data component populated with all its attributes from the profile (name, relative position, ...) All the above representation allow you to switch from one to the other. We even have a pretty print so we can decipher message when investigating bugs. We also have a DSL to create messages from code to promoto some brevity when creating messages and lax us fro having to precisely order fields when writing code. Couldn't one say that a dsl is yet another more domain specific representation of the medical record? Why did you code against the medical record rather than the dsl? My assumption is that the dsl is just a subset but just curious. None of the above uses defrecord or deftype. We use Clojure's persistent structures and protocols to implement how to handle these various formats. Roughly we do this in less than 1000 lines splitted in 4 namespaces. This code never refers to a specific piece of data by its name. A bit confused. So you have profile that describes how to convert from the medical record to the preferred internal representation which allows you to support multiple medical record representations? How might you handle the situation where a new medical record contains an abbreviation or medical code but you need the full value and to get the complete value you need to perform a web service query, so you want to avoid this unless the value is required... Ideally, the internal representation would know that the value is expensive and to request it only if necessary. So This would probably change the contract, but for your boss needs this to process this non-standard record format tomorrow if the client likes what he sees youll have time to support it properly, if not then you can just rip the code put. How would you go about this change 1 if you needed it functional tomorrow and 2 the ideal/best way? It's all data driven, the contract is data in our internal protocol profile definition. Validation, searching the metadata of the profile, ... is done within the profile definition. So do you have one function that takes the profile, record and desired property? The name spaces allowing us to support the different representations all rely on the profile definition. They never refer to specific data items. Some devices do not support all the fields or are using older versions of protocols compared to what we implemented internally. We have a rule engine and rules attached to specific device profiles to alter the common format message so we can spit out a valid message that can be understood by the device. We implemented a Clojure protocol that lets us manipulate a message using Clojure generic fns to strip items, swap items from one spot to the other, These rules are applied on top of a generic message just before sending or just after receiving to/fro the device. We do not have to recode messages for each device type. This is the only place aside from message generation that will ever refer to specific data items. What about maintenance ? Why remove a data item from the profile ? If ever necessary, we can flag it as unusable and the rest will carry on. Any attempt to refer to it will trigger an exception. Searching the code base to find references to it is no more difficult than finding getters. And we know it's a required change. Either it disappeared or the data item changed. We can remove it somewhere in the future, no need rushing. It eases the maintenance of the device specific rules, if they do not refer to the disabled data item, they are still working. We get a uniform way of dealing
Re: Doseq, map-style
On Sunday, June 17, 2012 8:48:58 AM UTC-6, Vinzent wrote: Well, if those assertions are violated, you can't do anything with it anyway - you program is written wrong and you have to release new version which'll fix it. Yes, but if data in your database become corrupt then you may need to do more than just release a code fix воскресенье, 17 июня 2012 г., 1:41:17 UTC+6 пользователь Alex Baranosky написал: To test for violations of those assertions, possibly due to wonky data that only occurs in certain production-only circumstances. -- 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
Re: Doseq, map-style
On Sunday, June 17, 2012 9:09:23 AM UTC-6, Vinzent wrote: This still requires changing your code to @(:emails contact). If you use (emails contact) you need change your code in only one place. The name emails implies that it's a sequence. Lazy sequence. Yes it is... emails was not the best example in this case.. think the area example instead as this is single value rather than collection. Lazy sequences also introduce additional problems... they maybe realized when bindings are no longer in effect which causes all sorts of non-local errors with stacktraces that are completely non-intuitive. Property is just the OO word for function, semantically they are the same. OO doesn't have functions they have properties and methods. I thought the concept similar to function in OO-world is method. Ok, so if property is a function, then you want to get rid of data structures at all and have only functions? Yes, always access a map value via a function, this provides a seam (see Feathers, Working Effectively with Legacy Code http://www.informit.com/articles/article.aspx?p=359417) where alternative behavior could be introduced. Keywords are functions, but their behavior cannot changed therefore they do not make for useful seams. The data still needs to be stored some where so you will have maps and will still need to use keywords to access that data... but that keyword usage should be in only one place so that when you do change the data structure eventually you will need to only update that one function. Agreed, clojure has a much stronger emphasis on immutability than traditional OO programming and is what I like about it... but it is possible to write OO code using immutable data structures but is not as idiomatic. Well, it's kind of idiomatic in scala, for example. But not in clojure, yes. Agreed, I did not like scala's excessive use of operators, implicit conversions and other syntax tricks. Plus the compiler is painfully slow. I don't want clojure to be like CLOS, but I also don't think that we should ignore more than 50 years of lessons learned and SOLID programming principles. SOLID is about object-oriented design. 50 years of lessons learned tell us that objects have failed :) I disagree. I don't think OO has failed us...MOST software is written in OO languages. Lisp and various functional languages are much older than OO, yet were not widely adopted for commercial use. I'm not saying OO is perfect or that there is no room for improvement, thats why I tried clojure in the first place, but perhaps OO has been far more successful then you give it credit for and certainly more successful in practice then these so called academic languages. -- 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
Re: Doseq, map-style
On Jun 17, 2012, at 10:45 AM, Vinzent ru.vinz...@gmail.com wrote: Yes it is... emails was not the best example in this case.. think the area example instead as this is single value rather than collection. Well, I thought we've already came to the agreement that area is a (polymorphic) function and it has nothing to do with structure of your data, no? Yes, what I am also saying is that width, height, radius etc may also be functions, if they are used by the domain they are should be a function. If they are not used by the domain they are an implementation detail and should not be accessed via keywords except of course by the single function that provides the seem. Lazy sequences also introduce additional problems... they maybe realized when bindings are no longer in effect which causes all sorts of non-local errors with stacktraces that are completely non-intuitive. Use bound-fn and similar tools to preserve the context. Use contract programming https://github.com/dnaumov/clojure-contracts to get rid of ugly stacktraces :) Anyway, these are other problems not related to the topic. Yes there is that, but this is doesnt resolve all problems with bindings... Perhaps a different topic, but arent we already off topic :) Yes, always access a map value via a function, this provides a seam (see Feathers, Working Effectively with Legacy Code http://www.informit.com/articles/article.aspx?p=359417) where alternative behavior could be introduced. Keywords are functions, but their behavior cannot changed therefore they do not make for useful seams. The data still needs to be stored some where so you will have maps and will still need to use keywords to access that data... Well, accessing a map value via a function is what object-oriented programming is about. So your concern is about the fact that clojure isn't object-oriented? I thought you was talking about using functions to model all other data structures, which is a good idea in theory, but is not very practical. but that keyword usage should be in only one place so that when you do change the data structure eventually you will need to only update that one function. Changing data structure == changing API. If you change an interface in Java how many updates you'd have to do? Data structure is an implementation detail... interfaces are contracts, if the data representation changes in OO you need only change one class... In clojure, you need to change every usage. This is speaking from first hand experience when I made trivial changes that would be a one liner in java took hours and introduced simple bugs, wring usage, typo whatever. This is exactly the point of my post, if you wrap keywords and treat them as one does properties this could be a one liner in clojure too... I disagree. I don't think OO has failed us...MOST software is written in OO languages. A million lemmings can't be wrong. Sure. I'm not blindly advocating the use of simple abstractions just because that what some/many OO programmer suggests is best practice... but because personal experience has given me enough conviction to believe they add value even if they add a few LOC... And that it is worth arguing about a bit... even if this means I am not following idiomatic clojure practices that I disagree with. I don't agree with all OO practices either..mutable collection types, excessive over engineering... All patterns have some trade offs, but one LOC for a seam is well worth it imo. Lisp and various functional languages are much older than OO, yet were not widely adopted for commercial use. That's not true - they were. I'm not saying OO is perfect or that there is no room for improvement, thats why I tried clojure in the first place, but perhaps OO has been far more successful then you give it credit for and certainly more successful in practice then these so called academic languages. Java is successful for commercial reasons, not because it's the best language ever written. -- 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 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
Re: Doseq, map-style
On Sunday, June 17, 2012 1:41:22 PM UTC-6, Vinzent wrote: That is my point, representations SHOULD be considered implementation details, because representations change... if you treat them as contracts your code will break everywhere, if you wrap them with abstractions your code will only need to change in one place... As I mentioned above, this will lead us to objects instead of data. Also, many people write code without (def foo :foo) and their code isn't breaking (or at least they are hiding it carefully!), so this statement does not match the reality, isn't it? But I have made this point before and starting to feel like the conversation is going in circles. Yeah, it definitely is. I have made several reasoned arguments for getter functions... Which arguments? We found that :emails is a lazy seq and area is a function... Could you provide a certain examples where plain maps don't work, so we could highlight pros and cons and figure out the best way to work around it? If you disagree thats fine. But the only well reasoned argument why one should not use them except that it adds an extra lines of code to maintain and imo LOC is a poor metric for maintainability. No, the argument is that it replaces data with unstructured objects, making clojure sequence api inapplicable. Also, it's impossible to use destructing, pattern matching, testing frameworks functionality and walkers anymore. Moreover, since clojure doesn't support this approach out of the box, you'd have to write and maintain some macros in order to avoid duplication. Generally, I think it can make reading the code more difficult for other people. This is actually the most compelling argument which I didn't give you credit for. However, if you follow the hollywood principle you don't need a seq abstraction. Instead you use pipes and filters and this enables distributing computation across multiple machines without the synchronization bottleneck introduced by list concatenation. Ruby and python make this easy with first class functions and each() blocks. Clojure however might be the worst case, because it requires making seq abstraction part of the contract and in turn creates a dependency on the data structure which in turn creates the need for the getter abstraction in the first place. The need for getters is often an indication that the hollywood principle has been violated, and in clojure this principle is violated more often than it is not in the name of side-effect free functions. Haskell uses monads and this makes functions not only pure but also applies the hollywood principle. I would love to use more Haskell... but I don't think Haskell will ever run on the JVM and even if it ever did the Java libraries would pretty much need to be blacklisted and it wouldn't be all that useful... I thought clojure had potential due to its focus on immutability, but I think the hollywood principle is more important than side-effect free and this was the point of my original reply before we got off topic about abstracting implementation details. If you follow the hollywood principle you don't need getters... but you do need side-effects. It actually seems silly in retrospective to go on and on about the value of getters in OO programs I avoid them like the plauge... but in OO I have the hollywood principle in clojure getters are the only abstraction to protect my code from changes to data representations. -- 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
Re: Doseq, map-style
On Sunday, June 17, 2012 6:31:34 PM UTC-6, Sean Corfield wrote: On Sun, Jun 17, 2012 at 11:59 AM, Kurt Harriger kurtharri...@gmail.com wrote: That is my point, representations SHOULD be considered implementation details, because representations change... if you treat them as contracts your code will break everywhere, if you wrap them with abstractions your code will only need to change in one place... Have you watched Stu Halloway's talk about the design of Datomic? Evident Code, at Scale: http://www.infoq.com/presentations/Evident-Code-at-Scale You said earlier in this thread that Clojure is your first Lisp so it's possible (likely?) you don't yet realize how different it is to the languages you're used to. If you watch several of the presentations by Stu Halloway and Rich Hickey and some of the other Clojure/core folks, you should get an appreciation of why data-as-API is reasonable in Clojure, in the same way that interface-as-API is reasonable in Java. It's an immutable contract. It can be operated on by all the standard Clojure functions but it's still a contract. It is not necessarily the representation - it is the API you present to the world. You can change the representation any way you want and if the API does not change (in the same way that an interface wouldn't change in Java), then you continue to present the same data structure to client code, even if it is now a projection of the representation, rather than the representation itself. I didn't get a chance to see it, before but watching it now and he says a couple interesting about abstractions right off at the beginning ideal number of abstractions 0. We abstract to much interfaces are too large etc... One of the sayings I hear reiterated is it is better to have 100 methods that operate on one data structure than 10 methods that operate on 10 data structures. Yet how is this different from one large interface with a hundred methods? Now if you want to change a map so that :area which was previously an precomputed value to a deferred computation you now need to override ILookup, ISeq IMapEntry, perhaps others to ensure keyword lookups and destructuring works etc... so while some see clojure as removing unnecessary abstractions I see it as adding creating one bloated abstraction around a persistent map which is hard to change due to the number and complexity of the built-in abstractions then 1 function that is relevant to my problem domain. I have also found that clojure code lacks cohesion we hate objects so we are just going to throw everything into one large namespace and say we have none... In OO I might call this a god class? I don't know, I'm not sold yet... but I'll keep watching. I like the data as api idea in theory, as it encourages declarative programming and really thinking about the problem. I don't disagree that many java abstractions could be considered premature and could be added later if needed... but sometimes they really are needed. I discussed this before in regards to HTML that dependance on representation can limit the ability to quickly implement new features... In the beginning html probably didn't need any additional abstractions but as the usage and domain complexity increased it turned into a mess that requires apis to both read and write those data structures. I was very excited about using clojure a year ago and now that I've spent a few months with it I've been very frustrated... Its possible something just hasn't quite clicked yet, but I'm also beginning to notice issues in other apis. Many libraries have been deprecated, replaced and rewritten due to breaking changes to clojure core or other libraries and that worries me a bit.. but clojure is still maturing and no one gets the abstractions exactly right the first time so I'm kinda going back into a wait and see mode...but I can't sit on the side lines entirely cause I just wrote a reasonably complex clojure program that I need to maintain still :) I have made several reasoned arguments for getter functions... If you disagree thats fine. Your arguments are reasoned for Java and its ilk because in those languages, data structures are just representation details - and they are mutable, so they can't possibly be an API. Your arguments are not reasoned for Clojure because data structures cannot be modified by client code - they _can_ be the API, and an API that can be used directly by map / filter / reduce and all the sequence functions and so on. Vincent said: Well, but if interfaces change? That's the same as data representation change in clojure. This is the fundamental shift in thinking that immutable data-as-API requires. It's how you get some of the real benefits from Clojure. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com
Re: Doseq, map-style
On Jun 17, 2012, at 9:38 PM, Timothy Baldridge tbaldri...@gmail.com wrote: I have also found that clojure code lacks cohesion we hate objects so we are just going to throw everything into one large namespace and say we have none... In OO I might call this a god class? I don't know, I'm not sold yet... but I'll keep watching. That depends. In OOP we might call it a God Class if it was 100 functions on a single mutable class. However, that's not what we're doing in Clojure. The analogy to OOP would would be a class with 100 static public members, and no private variables. This exact methodology is used in .NET for example: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aspx Now if you want to change a map so that :area which was previously an precomputed value to a deferred computation you now need to override ILookup I hear this argument at work dealing with Stored Procs in the SQL database. If you don't let me do ad-hoc queries, then when you change the sproc, you're going to break all our code!. But the correct answer to this complaint is: I won't. If you need to change area from pre-computed to defered execution, then you are changing the actual semantics of the code. In that case, yes, you will either need to define a different data api, or update all your old code to agree with the new computation method. Most of the time, if you have code in production, sticking with the first is the better route. Generally agree During the day, I work on a fairly large C# codebase, and I see these same problems, but they are simply ignored by most .NET programmers. If I call Foo.getBar(). I haven't the foggiest clue where on earth it's going to get the data I want. It could be computing the value, or simply returning a private variable, or it could be going to Mars to gather a soil sample and use that in its calculation (blocking me until it returns). That's one of the benefits of the everything is a map method. I know that calling (:bar data) is going to return almost instantly. You can re-write your data server to involve Mars trips, but once the data is in my program, my code will remain snappy, no matter how long it took to compute that data. Forget about getters, OO should be event driven in which case you dont call getFoo(), foo is given to you when your method is invoked making getters unnecessary. The clojure problem is different because events imply side effects. Although, I have never seen a program that does not have side effcts. I tried to write one once but it had no output so im not sure if it actually worked :) So I guess what I'm saying is that if you're deciding to switch area from pre-computed to lazy execution, that's such a major change semantically that you better reevaluate your code before simply abstracting it and calling it a day. True too. But then again, I'm biased. I deal with so many layers of abstraction at my day job sometimes I just want to stand up from my desk and shout A hashmap! My kingdom for a hashmap!. I programmed in C# for years but changed to JVM cause windows isnt a good platform for web apps. I turned to clojure for many of these same reasons, i love that clojure values are immutable, serializable, and implement meaningful equality with basicaly no code. Pojos/message types should have these things :) but i think services classes should be event driven and emit new events rather than return values and delegate much of the work to the domain. I guess i feel like clojure consists only of pojos and god classes... Timothy Baldridge -- 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 a http://groups.google.com/group/clojure?hl=en -- 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
Re: Doseq, map-style
On Jun 17, 2012, at 9:46 PM, Sean Corfield seancorfi...@gmail.com wrote: On Sun, Jun 17, 2012 at 8:06 PM, Kurt Harriger kurtharri...@gmail.com wrote: One of the sayings I hear reiterated is it is better to have 100 methods that operate on one data structure than 10 methods that operate on 10 data structures. Yet how is this different from one large interface with a hundred methods? You've misunderstood the intent behind the quote. By using a generic data structure, you have more functions available to you - and you don't have to duplicate each function for each different data type (10 methods that operate on 10 data structures is 100 methods but really only 10 different ones). By using a generic map, all functions that work on maps are available to you. By choosing a specific data structure for your object, you are forced to write a new version of every function you might need. Your one line getters might be trivial enough (one for every property) but now you can't use your object with any function that takes an associative data structure and you have to write adapter functions for each of those functions too. Now if you want to change a map so that :area which was previously an precomputed value to a deferred computation you now need to override ILookup, ISeq IMapEntry, perhaps others to ensure keyword lookups.. This is an API change, just like changing a Java interface. In OO-land folks get very blasé about changing data structures because they obsessively wrap everything up and they seem to ignore all the extra code they have to write to do anything with these objects. By designing an API based on a data structure, there's a lot less code needed to interact with it. If you change the API, yes, client code needs to change, just like in Java. If your object's API changes so that area is not precomputed and becomes a deferred computation, that is still a change to the contract (because the performance of accessing area changes - and calling getArea() repeatedly now becomes expensive rather than a trivial operation). If you're designing a data-based API, you need to consider what to provide and what the characteristics of each part of the data structure are, just as you need to with a Java interface. What's missing in Java interfaces are any consideration about performance and what the abstraction really means. A fair point, getters dont really solve the problem they just change it. The problem i had was generating large complex data structures as input to other functions made me realise the representation was not ideal, changing it however was much more work than I expected. I find that what i am doing is creating a new namespace, copying the code, change it then go about replacing the old namespace with the new and this isnt working well for me I need seams for refactoring otherwise small changes take forever. I wish i could say that my code improves each time i rewrite it but as the complexity increases the more things change and the worse everything else gets. In oo i know how to handle this complexity, in clojure the refactoring patterns are less clear to me. Its possible something just hasn't quite clicked yet Quite possible. If you have a long history of OO thinking, FP can be really hard to get into. I find it much easier to teach FP to folks who've had little or no OO experience. Getting OO folks away from thinking about state as something inside an object that they can just poke at can take a while :) Many libraries have been deprecated, replaced and rewritten due to breaking changes to clojure core or other libraries and that worries me a To be fair, the shift in contrib from 1.2 to 1.3 was more about getting rid of unmaintained code and ad hoc experiments and focusing instead on well-maintained libraries that are useful to real world developers. Several of the authors of the abandoned parts of monolithic contrib will be very quick to tell you not to use their old code because it was half-baked or otherwise flawed... I can't sit on the side lines entirely cause I just wrote a reasonably complex clojure program that I need to maintain still :) And I have thousands of lines of Clojure in production too, and a database with millions of users - and thousands more signing up every day. We started on Clojure 1.2 but switched to 1.3 early on and went to production with Alpha 7 (or 8) and now we're on Clojure 1.4 (and testing on nightly builds of 1.5, just to be sure we're future proof). Where we needed libraries from 1.2 that were not 1.3 compatible, we made them compatible and worked with the library maintainers as much as we could. clojure.contrib.sql moved to clojure.java.jdbc and is actively maintained because of that. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French
Re: Doseq, map-style
On Wednesday, June 13, 2012 2:52:15 AM UTC-6, Vinzent wrote: I do use pre-conditions where the test condition is simple, ie is this a string? does the map have a :field-type? however I get a lot of my input data from http requests as json which have similar structures but different semantics, so I often do not have preconditions where type is not explicit. For example a string could be an list id or a contact id or an encoded json document. While it is possible to try to parse a string for json to verify its type this is seems very computationally expensive and therefore usually inferred from the context. Why do you care about computational expensiveness of pre and post conditions? They'll be turned off in production anyway. How does one turn off pre/post conditions in production? I agree with Sean however and generally think that assertions in production a bad thing. For example, my first contact model I had {... :fields [{:field-type :email :value ...}]} I later realized that the endpoint to get the contact information provided them grouped and I was filtering a lot based on field-type anyway so a more effective data structure was {:emails [{:value ...}]}, :field-type was just an implementation detail, the email object still has a value and associated behavior but the map no longer contains a :field-type. However, phone numbers have exactly the same {:value } structure so the only way to determine if it is an email or a phone number is from context or by parsing the string. I believe using records or adding :type metadata would be an ideal fit in this case. I agree, an explicit type field makes dispatching easy. However this data structure returned by (http/get ... :as json) so if I want to add type information I need to walk the tree and rewrite it. Not necessarily a bad idea, but in some cases the only thing I need is the eTag and so the additional processing may in some cases unnecessary. One could easily make data conversions lazy by doing something like (defrecord Contact [contact]) (defmethod emails Contact [contact] (map map-Email (:emails contact)) to delay the computation until the values are actually requested. However, note that emails is now a multimethod method not a value and the consumer needs to use (emails contact) rather than (:emails contact)... Thus as I was saying previously is that (def emails :emails) gives you the flexibility to delay computation if desired. I also tried using multimethods instead of protocols, but I still found I needed to restart the JVM frequently. I think whenever I would re-eval the namespace with the record type and (defmethod ...) a new class file would be emitted and the objects in my swank session need to be recreated. defmulti has defonce semantic; you can use (def foo nil) (defmulti foo ...) to workaround this. A topic about this problem was recently created in dev mail list, so it'll probably be fixed soon. I disagree. Ironically, if you told a java developer that getters were a premature optimization and he should use fields instead he would look at you funny. Getters are not an optimization and if anything have a minor performance penalty. However, using fields makes one very dependent on implementation details doing so is considered bad practice. I don't see how this is any different in clojure. In clojure, structure of your map is a part of the contract. It's not an implementation detail - it's the same as getters\setters in java. EXACTLY my point! Clojure does not distinguish between properties and data representation and these are NOT the same thing. There are many different ways to represent data. For example the area of a shape can be represented in many different ways, square inches, square miles, a rectangle, circles, polygons, or perhaps complex geometry requiring calculus all of which could be asked what is your area in square feet. Area is a property of the object, the width, radius, number of sides, etc is an implementation detail. You may then ask so why don't you just pass in {:area } as square feet instead of the radius of the circle? Because the value may not be used by the function. If its not used then why is it part of the contract? Because it may be used conditionally, for example, maybe the function needs to find the first shape that will fit within a region once that limit is reached it no longer requires the area for any other shapes. So if the shape requires complex calculus which has been written in another programming language and thus requires a rpc call to a network service to compute the value that is only used sometimes seems wasteful and inefficient if the value is only sometimes computed. This example is somewhat contrived, but it is not that different from what I am doing. For each contact record I need to perform data enrichment, normalization, cleansing, and
Re: Doseq, map-style
On Saturday, June 16, 2012 12:26:34 PM UTC-6, Sean Corfield wrote: On Sat, Jun 16, 2012 at 10:58 AM, Kurt Harriger kurtharri...@gmail.com wrote: How does one turn off pre/post conditions in production? (binding [*assert* false] (call-my-code)) I agree with Sean however and generally think that assertions in production a bad thing. I didn't say that. I said the question was a philosophical one. I actually think assertions should stay _on_ in production (so I would care about computationally intensive assertions - and I would prefer those to be in a test suite). Sorry, I mistyped that. I too agree that assertions should remain on in production. Sometimes my fingers don't keep up and I miss a word or two when that word is not the results can be disastrous. (and I don't agree with you on using accessor functions vs data-as-API either) I think there is a difference between data as an api and using data as a programming model. I am fond of declarative programming, say what not how. But, it is my opinion that good declarative data models require extremely good understanding of the problem domain which develops from reflecting of the commonality and differences in many different implementations. Declarative data models done right can simplify things... however, the wrong data model can also introduce complexity. Ant is a data driven api but the data model is poorly designed, maven is a much better example of a declarative data api, yet a lot of people still find maven to be more complex and inflexible than ant for various projects that require a lot of plugins. A really good clojure specific example of data vs api is the discussion regarding if the clojurescript analyzer should contain children or if children should be a multimethod https://groups.google.com/forum/m/?fromgroups#!topic/clojure-dev/vZLVKmKX0oc HTML is another great example of a declarative data model that has shown the stress of increasing complexity from poor representation for common use cases (its a navbar not a table) and a multiplicity of vendor specific additions that do the same thing in a different way. I don't think it is a stretch to say that rich client side web development was significantly more difficult to do correctly before apis such as jquery were written to abstract over the differences in vendor implementations. HTML is data as an api that tells the browser how to render a page it cannot be anything else... but I wouldn't consume or construct the data structure directly instead I would use an api such as jquery so that when the data representation changes such as new css attributes that enable the same effect to be accomplished more efficiently I can quickly take advantage of them without needing to make massive breaking code changes. APIs allow you to be DRY. I'm not suggesting that the api for a program should not be a declarative data structure, what I am saying is that we should not consume the data structure directly without abstractions. Publish your api as a data structure...consume that the data structure through an api. Kurt -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) On Saturday, June 16, 2012 12:26:34 PM UTC-6, Sean Corfield wrote: On Sat, Jun 16, 2012 at 10:58 AM, Kurt Harriger kurtharri...@gmail.com wrote: How does one turn off pre/post conditions in production? (binding [*assert* false] (call-my-code)) I agree with Sean however and generally think that assertions in production a bad thing. I didn't say that. I said the question was a philosophical one. I actually think assertions should stay _on_ in production (so I would care about computationally intensive assertions - and I would prefer those to be in a test suite). (and I don't agree with you on using accessor functions vs data-as-API either) -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- 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
Re: Doseq, map-style
On Saturday, June 16, 2012 1:28:21 PM UTC-6, Vinzent wrote: I agree, an explicit type field makes dispatching easy. However this data structure returned by (http/get ... :as json) so if I want to add type information I need to walk the tree and rewrite it. Not necessarily a bad idea, but in some cases the only thing I need is the eTag and so the additional processing may in some cases unnecessary. One could easily make data conversions lazy by doing something like (defrecord Contact [contact]) (defmethod emails Contact [contact] (map map-Email (:emails contact)) to delay the computation until the values are actually requested. However, note that emails is now a multimethod method not a value and the consumer needs to use (emails contact) rather than (:emails contact)... Thus as I was saying previously is that (def emails :emails) gives you the flexibility to delay computation if desired. You have delays and lazy sequences for delaying computation. This still requires changing your code to @(:emails contact). If you use (emails contact) you need change your code in only one place. Clojure does not distinguish between properties and data representation and these are NOT the same thing. Properties is OOP concept; clojure is not an object-orinted language. There are many different ways to represent data. For example the area of a shape can be represented in many different ways, square inches, square miles, a rectangle, circles, polygons, or perhaps complex geometry requiring calculus all of which could be asked what is your area in square feet. Area is a property of the object, the width, radius, number of sides, etc is an implementation detail. No, area is a function. Property is just the OO word for function, semantically they are the same. OO doesn't have functions they have properties and methods. You may then ask so why don't you just pass in {:area } as square feet instead of the radius of the circle? Because the value may not be used by the function. If its not used then why is it part of the contract? Because it may be used conditionally, for example, maybe the function needs to find the first shape that will fit within a region once that limit is reached it no longer requires the area for any other shapes. So if the shape requires complex calculus which has been written in another programming language and thus requires a rpc call to a network service to compute the value that is only used sometimes seems wasteful and inefficient if the value is only sometimes computed. This example is somewhat contrived, but it is not that different from what I am doing. If getting a 'property' requires such computations, then it's clearly should be a function. Agree. My point is that properties with getter functions allow you to defer computation, keywords do not. Keywords are not like java getters they are like java fields. Keywords are just one of clojure's data structures (see http://clojure.org/data_structures#Data Structures-Keywords) Instead of (:property themap), one should use (def property :property) (property themap). No, one shouldn't. I disagree... but I will continue to recommend otherwise. Actually this is only somewhat contrived. It is not uncommon for a user to the same nickname in his email nickn...@domain.com and in twitter handle, and this is a useful similarity feature when this computation is performed for each *pair* of field in each *pair* of contacts this computation may need to be performed millions of times. Well, you can use memoization or choose to structure your data in some other way. Perhaps lisp programmers already did? CLOS and OO was born? Clojure is not Common Lisp. Agreed, clojure has a much stronger emphasis on immutability than traditional OO programming and is what I like about it... but it is possible to write OO code using immutable data structures but is not as idiomatic. I don't want clojure to be like CLOS, but I also don't think that we should ignore more than 50 years of lessons learned and SOLID programming principles. -- 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
Re: Doseq, map-style
-- Kurt Harriger Sent with Sparrow (http://www.sparrowmailapp.com/?sig) On Saturday, June 16, 2012 at 3:07 PM, Kurt Harriger wrote: On Saturday, June 16, 2012 1:28:21 PM UTC-6, Vinzent wrote: I agree, an explicit type field makes dispatching easy. However this data structure returned by (http/get ... :as json) so if I want to add type information I need to walk the tree and rewrite it. Not necessarily a bad idea, but in some cases the only thing I need is the eTag and so the additional processing may in some cases unnecessary. One could easily make data conversions lazy by doing something like (defrecord Contact [contact]) (defmethod emails Contact [contact] (map map-Email (:emails contact)) to delay the computation until the values are actually requested. However, note that emails is now a multimethod method not a value and the consumer needs to use (emails contact) rather than (:emails contact)... Thus as I was saying previously is that (def emails :emails) gives you the flexibility to delay computation if desired. You have delays and lazy sequences for delaying computation. This still requires changing your code to @(:emails contact). If you use (emails contact) you need change your code in only one place. Clojure does not distinguish between properties and data representation and these are NOT the same thing. Properties is OOP concept; clojure is not an object-orinted language. There are many different ways to represent data. For example the area of a shape can be represented in many different ways, square inches, square miles, a rectangle, circles, polygons, or perhaps complex geometry requiring calculus all of which could be asked what is your area in square feet. Area is a property of the object, the width, radius, number of sides, etc is an implementation detail. No, area is a function. Property is just the OO word for function, semantically they are the same. OO doesn't have functions they have properties and methods. You may then ask so why don't you just pass in {:area } as square feet instead of the radius of the circle? Because the value may not be used by the function. If its not used then why is it part of the contract? Because it may be used conditionally, for example, maybe the function needs to find the first shape that will fit within a region once that limit is reached it no longer requires the area for any other shapes. So if the shape requires complex calculus which has been written in another programming language and thus requires a rpc call to a network service to compute the value that is only used sometimes seems wasteful and inefficient if the value is only sometimes computed. This example is somewhat contrived, but it is not that different from what I am doing. If getting a 'property' requires such computations, then it's clearly should be a function. Agree. My point is that properties with getter functions allow you to defer computation, keywords do not. Keywords are not like java getters they are like java fields. Keywords are just one of clojure's data structures (see http://clojure.org/data_structures#Data Structures-Keywords (http://clojure.org/data_structures#Data+Structures-Keywords)) Instead of (:property themap), one should use (def property :property) (property themap). No, one shouldn't. I disagree... but I will continue to recommend otherwise. I disagree... and I will continue to recommend otherwise. Actually this is only somewhat contrived. It is not uncommon for a user to the same nickname in his email nickn...@domain.com (mailto:nickn...@domain.com) and in twitter handle, and this is a useful similarity feature when this computation is performed for each *pair* of field in each *pair* of contacts this computation may need to be performed millions of times. Well, you can use memoization or choose to structure your data in some other way. Perhaps lisp programmers already did? CLOS and OO was born? Clojure is not Common Lisp. Agreed, clojure has a much stronger emphasis on immutability than traditional OO programming and is what I like about it... but it is possible to write OO code using immutable data structures but is not as idiomatic. I don't want clojure to be like CLOS, but I also don't think that we should ignore more than 50 years of lessons learned and SOLID programming principles. -- 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 (mailto: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
Re: Doseq, map-style
On Jun 16, 2012, at 6:27 PM, Softaddicts lprefonta...@softaddicts.ca wrote: 50 years of solid programming principles, OO being the Holy Grail ? :) I assume then that you programmed a lot in Simula-66 ? I did... For over 50 years, we made the same mistakes that Clojure attempts to correct. Most of the time new languages repackaged the same flawed concepts of the past, this has been done over and over again. How is clojure different? I have programmed in dozens of languages, message based and functional, static and dynamic, garbage collected and manage it yourself. One thing that I have realized is there is no magic bullet and they are as you say different versions of the same thing. Clojure is my first lisp however and I was really excited about it when I started but after writing a project with more than a few thousand lines of code I found it very frustrating to change. Programmer's throughput have to increase somehow, any superfluous line of code is too many. Getters facades of any form are just that, superflous code lines that need to be maintained later on. That led Java right in the russian puppet syndrom. In these 50 years solid principles, many failed to deliver. It's time for a reset :) I too have experienced the russian doll syndrome and logic scattered across multiple files, but I have already started migrating away from clojure because the code is difficult to maintain. If the code does not need to change then maintaining it is easy, however if it does need to change i would prefer to make that change in only one place. DRY. If that only requires one more line of code then I think it is well worth it and I certainly do not believe that lines of code are the best metric of maintainable code. IMHO, Readability and good domain abstractions are FAR more important then LOC. Luc On Saturday, June 16, 2012 1:28:21 PM UTC-6, Vinzent wrote: I agree, an explicit type field makes dispatching easy. However this data structure returned by (http/get ... :as json) so if I want to add type information I need to walk the tree and rewrite it. Not necessarily a bad idea, but in some cases the only thing I need is the eTag and so the additional processing may in some cases unnecessary. One could easily make data conversions lazy by doing something like (defrecord Contact [contact]) (defmethod emails Contact [contact] (map map-Email (:emails contact)) to delay the computation until the values are actually requested. However, note that emails is now a multimethod method not a value and the consumer needs to use (emails contact) rather than (:emails contact)... Thus as I was saying previously is that (def emails :emails) gives you the flexibility to delay computation if desired. You have delays and lazy sequences for delaying computation. This still requires changing your code to @(:emails contact). If you use (emails contact) you need change your code in only one place. Clojure does not distinguish between properties and data representation and these are NOT the same thing. Properties is OOP concept; clojure is not an object-orinted language. There are many different ways to represent data. For example the area of a shape can be represented in many different ways, square inches, square miles, a rectangle, circles, polygons, or perhaps complex geometry requiring calculus all of which could be asked what is your area in square feet. Area is a property of the object, the width, radius, number of sides, etc is an implementation detail. No, area is a function. Property is just the OO word for function, semantically they are the same. OO doesn't have functions they have properties and methods. You may then ask so why don't you just pass in {:area } as square feet instead of the radius of the circle? Because the value may not be used by the function. If its not used then why is it part of the contract? Because it may be used conditionally, for example, maybe the function needs to find the first shape that will fit within a region once that limit is reached it no longer requires the area for any other shapes. So if the shape requires complex calculus which has been written in another programming language and thus requires a rpc call to a network service to compute the value that is only used sometimes seems wasteful and inefficient if the value is only sometimes computed. This example is somewhat contrived, but it is not that different from what I am doing. If getting a 'property' requires such computations, then it's clearly should be a function. Agree. My point is that properties with getter functions allow you to defer computation, keywords do not. Keywords are not like java getters they are like java fields. Keywords are just one of clojure's data structures (see http://clojure.org/data_structures#Data Structures-Keywords) Instead of (:property themap), one should use (def property
Re: Doseq, map-style
On Tuesday, June 12, 2012 2:18:03 AM UTC-6, Christophe Grand wrote: Hi, To contrast our experiences of the language and the different approaches to deal with some problems: On Sun, Jun 10, 2012 at 4:47 AM, Kurt Harriger kurtharri...@gmail.comwrote: Many will say that side-effecting functions are more difficult to test then pure functions... However after writing about 4000 lines of clojure code, I realized that things in practice are never quite as simple as they seem. As functions are composed the data structures they work with grow larger and more complex and this leads to maps containing maps containing lists containing maps and a minor change downstream can ripple through the program. Tests become significantly more complex and fragile as the input and output structures grow in complexity. Do you test only the functions or do you have also introduced lint functions which check the shape of your data. To me, these are pretty useful: you can use them in tests, pre/postconds, middlewares to guard against untrusted sources etc. I do use pre-conditions where the test condition is simple, ie is this a string? does the map have a :field-type? however I get a lot of my input data from http requests as json which have similar structures but different semantics, so I often do not have preconditions where type is not explicit. For example a string could be an list id or a contact id or an encoded json document. While it is possible to try to parse a string for json to verify its type this is seems very computationally expensive and therefore usually inferred from the context. I also felt that explicit type checking went against the spirit of duck typing, there was a couple of times I added type checks only to realize that the type checking was to strict... ie nil was an acceptable value and now the code through an assertion error. In many cases a function simply takes the argument and passes it to another function, so I don't really care what type the argument is as long as there is an implementation of the other function which supports that data type, maybe it doesn't know but in the future maybe it will should my code unnecessarily constrain the type based on an implementation detail? I have never been truely sold on duck typing however as I often find the time I spend debugging exceptions thrown deep down in the call stack because an error that could have been caught earlier when the problem was obvious was allowed to penetrate deep into call stack where the problem is no longer obvious often within a third party library that never expected that type of input. In OO the argument is an interface which says nothing about the structure of the object, only that it provides the desired behavior. Protocols are a step in this direction, however, if you extend a protocol to a map then (satisfy? TheProtocol {}) will return true for ALL maps, making satisfies? an otherwise useless precondition. For example, my first contact model I had {... :fields [{:field-type :email :value ...}]} I later realized that the endpoint to get the contact information provided them grouped and I was filtering a lot based on field-type anyway so a more effective data structure was {:emails [{:value ...}]}, :field-type was just an implementation detail, the email object still has a value and associated behavior but the map no longer contains a :field-type. However, phone numbers have exactly the same {:value } structure so the only way to determine if it is an email or a phone number is from context or by parsing the string. This reminded me of another OO code smell Don't talk to strangers and the Law of Demeter, instead sending and returning maps of lists of maps I started returning maps of functions. This provided additional decoupling that enabled me to refactor a bit more easily additionally maps of maps of lists of maps often need to be fully computed where as a map containing functions allows me to defer computation until it is actually required which may in many cases be never. Basically you are returning a lazy map a map of keys to delayed values (why not use delays instead of fns as values?), while it is sometimes a necessity to do so, the implied trade-off must not be overlooked: the map can't be treated as a value anymore: if you call twice the pure function which generates such a lazy map twice with the same arguments, you get two lazy maps which are not equals! I'm not even speaking about being equal to their non-lazy counterparts (which makes them a bit harder to test) This is an excellent point. Initially I started passing maps of functions into other functions as optional parameter map for testing (new-correction [ {:keys [get-current-date] :or [get-current-date get-current-date]). This solved one problem but created others, the function was now completely deterministic and easy to test
Re: Doseq, map-style
You could also (dorun (map f coll)) It is actually interesting you brought this up as I was recently contrasting the OO principle tell don't ask with the functional way of doing things. In OO a void method taking a visitor is preferred over return values. One could perhaps say that (dorun (map f (generator))) is pretty much the same thing as (each (generator) f) except that generator is now a pure side effect free function where as visitors generally speaking have side effects, although this isn't required for example (each coll identity) is just as easy to use and test. The more I thought about it the more I began to realize that the OO visitor approach may still have some advantages over the functional approach. In a typed language the generator can overload based on the visitor's type signature, this makes refactoring and evolving code easier while still preserving backward compatibility as different versions of a visitor might have different method parameter types. Of course you could do this in clojure explicitly but is less elegant ie (map f (generator :non-default-type)) and is generally considered confusing to have functions return different return types depending on their parameters. It is probably better to just choose a different function name instead. One other difference that is not as easy to emulate functionally is when the generator spawns multiple threads and delegates the work where each worker may call the visitor back on different threads. In clojure you can easily (pmap f (generator)), however this requires generator to create a sequence of return values from a specific thread regardless of how many threads are used to generate the sequence or process the sequence, ultimately the generator must first bring all these results together on a single thread creating a synchronization bottleneck that does not necessarily need to exist when using side effects instead of return values. For example, the side effect might be to write its results to a database and the generator might partition the work to each visitor never expecting a reply from any of them, the visitor might even forward the request to a different machine on the network since no return value is expected or required. Many will say that side-effecting functions are more difficult to test then pure functions... However after writing about 4000 lines of clojure code, I realized that things in practice are never quite as simple as they seem. As functions are composed the data structures they work with grow larger and more complex and this leads to maps containing maps containing lists containing maps and a minor change downstream can ripple through the program. Tests become significantly more complex and fragile as the input and output structures grow in complexity. This reminded me of another OO code smell Don't talk to strangers and the Law of Demeter, instead sending and returning maps of lists of maps I started returning maps of functions. This provided additional decoupling that enabled me to refactor a bit more easily additionally maps of maps of lists of maps often need to be fully computed where as a map containing functions allows me to defer computation until it is actually required which may in many cases be never. Although very idiomatic to use keywords to get from maps, I have started to think of this as a code smell and instead prefer to (def value :value) and use this var instead of the keyword because it allows me to later replace the implementation or rename properties if it is necessary to refactor and I want to minimize changes to existing code or make changes to the existing code in small incremental units rather than all at once. It is also very hard to write a useful program that does not contain side-effects or reads data from an impure datasource and I used midje to mock functions that such as (get-current-time), many times my function did not use that function directly but was used by another function that my function called. I began to see this as a code smell in OO I would mock the object that uses get-current-time not get-current-time itself which then gave me the idea to start passing the functions used by the function under test to the function as additional parameters, for testing I could pass in an alternative function such as (constantly true) or (identity). However, some functions required many functions so I began to group these into maps and began to realize that I was reinventing OO programming... perhaps there is a good reason lisp programmers invented CLOS in the first place. I'm starting to go off topic, and don't mean to troll, but your question as innocent as it seems is perhaps one of the most important differences between OO and functional programming (Tell don't ask). Perhaps the functional solution is monads... but most find these confusing for some reason and are hardly idiomatic. I
defrecord serialization and *data-readers*
When I first started my project I tried using defrecord and defprotocol for various data structurs and when I wanted an easy serialization function I used pr-str and read-string, this worked great!... until I wanted to do some refactoring and move some types to another namespace. After changing the namespace name, I could no longer read the serialized data structures since the serialized data included namespace and record type #namespace.Record{:prop value }. Ideally, I would just be able to redefine the reader literal for #namespace.Record so that I could define a custom function or perhaps alias it to an equivalent record type in a different namespace via *data-readers*, but this didn't seem to work for me. It appears that data-readers can't override the reader literals for record types and instead read-string throws a class not found exception. I have since stopped using record types for serialization and saving everything as maps, but this has increased the complexity of the deserialization logic as I need to store the type information in fields and restore these types after deserialization. I liked using record types, but I don't like not being able to rename these types later if I change my mind. It seems to me that I should perhaps be able to override the reader literals for record 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
Re: Clojure 1.3+ and JRebel
On Sunday, May 6, 2012 5:08:51 PM UTC-6, Anton Arhipov wrote: Tried both: java -javaagent:... -jar clojure.jar and java -javaagent:... - cp ... clojure.main -r Both seem to work fine. What does java -version print? java version 1.6.0_31 Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3646) Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode) -- 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
Re: Clojure 1.3+ and JRebel
Done. Thanks. -- 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
Clojure 1.3+ and JRebel
I'm attempting to start a swank-clojure session within a grails application. This part is easy and works fine. However, whenever I change a groovy class clojure does not see this change until I restart the jvm. I mucked around a bit with classlojure and pomegranate trying to figure out if I could shadow the default class loader to force clojure to relaod the groovy class files on demand, but at the moment it seems beyond me. I've heard of JRebel for reloading class files in an existing jvm and ran across a few posts where people have had success using JRebel to reload classes in clojure. I was able to get this to work with clojure 1.2.1 however I can't get it to work with clojure 1.3 or 1.4. The simplest reproducible test case I could think of was just to start the repl as follows: java -javaagent:/Applications/ZeroTurnaround/JRebel/jrebel.jar -cp lib/clojure-1.4.0.jar clojure.main -r JRebel: Starting logging to file: /Users/kurtharriger/var/jrebel.log [2012-05-05 16:19:40] [2012-05-05 16:19:40] # [2012-05-05 16:19:40] [2012-05-05 16:19:40] JRebel 4.6.2 (201205021440) [2012-05-05 16:19:40] (c) Copyright ZeroTurnaround OU, Estonia, Tartu. [2012-05-05 16:19:40] [2012-05-05 16:19:40] Over the last 1 days JRebel prevented [2012-05-05 16:19:40] at least 1 redeploys/restarts saving you about 0 hours. [2012-05-05 16:19:40] [2012-05-05 16:19:40] This product is licensed to Kurt Harriger (FullContact) [2012-05-05 16:19:40] until June 4, 2012 [2012-05-05 16:19:40] [2012-05-05 16:19:40] * [2012-05-05 16:19:40] Your license is about to EXPIRE! [2012-05-05 16:19:40] * [2012-05-05 16:19:40] [2012-05-05 16:19:40] This license will expire in 29 days and JRebel will [2012-05-05 16:19:40] stop working after that. Renew your license at: [2012-05-05 16:19:40] http://sales.zeroturnaround.com/?1338842936 [2012-05-05 16:19:40] [2012-05-05 16:19:40] The following plugins are disabled at the moment: [2012-05-05 16:19:40] * Apache MyFaces plugin (set -Drebel.myfaces_plugin=true to enable) [2012-05-05 16:19:40] Reloads JSF configuration and reconfigures managed beans. [2012-05-05 16:19:40] * Click plugin (set -Drebel.click_plugin=true to enable) [2012-05-05 16:19:40] Reloads menu.xml menu definitions of Apache Click projects. [2012-05-05 16:19:40] * JRuby Plugin (set -Drebel.jruby_plugin=true to enable) [2012-05-05 16:19:40] * Jersey plugin (set -Drebel.jersey_plugin=true to enable) [2012-05-05 16:19:40] Reloads Jersey configuration from Java annotations. [2012-05-05 16:19:40] * Oracle ADF Core plugin (set -Drebel.adf_core_plugin=true to enable) [2012-05-05 16:19:40] JRebel ADF Core Plugin [2012-05-05 16:19:40] * Oracle ADF Faces plugin (set -Drebel.adf_faces_plugin=true to enable) [2012-05-05 16:19:40] JRebel ADF Faces Plugin [2012-05-05 16:19:40] * Seam-Wicket plugin (set -Drebel.seam_wicket_plugin=true to enable) [2012-05-05 16:19:40] Integration with load time weaving seam annotations to wicket classes [2012-05-05 16:19:40] (-javaagent:path-to-jboss-seam-wicket-jar) [2012-05-05 16:19:40] * WebObjects plugin (set -Drebel.webobjects_plugin=true to enable) [2012-05-05 16:19:40] WebObjects JRebel Plugin [2012-05-05 16:19:40] [2012-05-05 16:19:40] # [2012-05-05 16:19:40] Exception in thread main java.lang.ExceptionInInitializerError at clojure.main.clinit(main.java:20) Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/first, compiling:(clojure/core.clj:55) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6462) at clojure.lang.Compiler.analyze(Compiler.java:6262) at clojure.lang.Compiler.access$100(Compiler.java:37) at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:518) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455) at clojure.lang.Compiler.analyze(Compiler.java:6262) at clojure.lang.Compiler.analyze(Compiler.java:6223) at clojure.lang.Compiler.eval(Compiler.java:6515) at clojure.lang.Compiler.load(Compiler.java:6952) at clojure.lang.RT.loadResourceScript(RT.java:359) at clojure.lang.RT.loadResourceScript(RT.java:350) at clojure.lang.RT.load(RT.java:429) at clojure.lang.RT.load(RT.java:400) at clojure.lang.RT.doInit(RT.java:436) at clojure.lang.RT.clinit(RT.java:318) ... 1 more Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/first at clojure.lang.Var$Unbound.throwArity(Var.java:43) at clojure.lang.AFn.invoke(AFn.java:39) at clojure.core$fn.doInvoke(core.clj:3999) at clojure.lang.RestFn.invoke(RestFn.java:490) at clojure.lang.Var.invoke(Var.java:431) at clojure.lang.AFn.applyToHelper(AFn.java:178) at clojure.lang.Var.applyTo(Var.java:532) at clojure.lang.Compiler.macroexpand1(Compiler.java:6366
clojure-1.4.0.jar missing in ~/.m2
When i first upgraded to clojure 1.4 i had a similar issue with lein not downloading updated dependencies. It tirned out to be an invalid version range dependency spec in midje that caused it to fail silently. Perhaps try removing all other dependencies first and try again. -- 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
LinkedHashMap not well supported
I am using a groovy library that returns a LinkedHashMap containing ArrayLists and nested LinkedHashMaps. I did not expect any issues working with this in clojure since this type implements java.util.Map I figured everything would just work. However the first thing I tried to do was apply clojure.set/keywordize-keys which didn't keywordize the keys as expected. I then tried map? which returned false, I figured I would then try to convert to clojure map using apply hash-map which threw an illegalargumentexception. into {} however did work. I then attempted to use clojure.walk/postwalk to convert LinkedHashMaps to clojure maps which only visited the top node. However using prewalk did work, so I ended up with the following helper function. (defn- convert-types [groovy-result] (walk/prewalk (fn [x] (cond (instance? java.util.LinkedHashMap x) (into {} x) (instance? java.util.ArrayList x) (vec x) ;; probably not required but I wanted to pr-str to print as vectors rather than #ArrayList ... :else x)) groovy-result)) clojure map? is defined as: (fn ^:static map? [x] (instance? clojure.lang.IPersistentMap x))) Is there any reason map? checks explicitly for clojure.lang.IPersistentMap rather than java.util.Map? also clojure.walk/walk contains: .. (instance? clojure.lang.IMapEntry form) .. but (first m) returns java.util.LinkedHashMap$Entry which extends java.util.Map$Entry and java.util.HashMap$Entry. I'm not sure why into {} works but apply hash-map doesn't, seems to have to do with first and next don't work on java.util.LinkedHashMap$Entry either. Seems like many of these functions could be improved to work with java.util.Map and java.util.Map$Entry? Should a JIRA be created for these? -- 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