3 ms·
This comment makes no sense to me, you don't like how clear it is? Somehow the clarity causes you to distrust what is actually happening? Every time I have to
by jhspaybar 13y ago
This comment makes no sense to me, you don't like how clear it is? Somehow the clarity causes you to distrust what is actually happening?
Every time I have to write something like
Calendar cal = Calendar.getCalendar();
cal.setDate(new Date());
cal.addDate(-2, Calendar.DAYS);
Date date = cal.getDate();
I want to claw my eyes out. Is this what you consider more clear, less cutesy, somehow more productive than just 2.days.ago ?
- wheaties 13y agoHow about this 2.days.from_last_update? What does it do? What is going on with "from_last_update"? Is it actually reaching out to a database to find the last updated value? Which database? How do you configure it? All these questions and more are why you should question "english as a DSL" methods. Granted, there's a ton of great libraries out there which do this well. Take Unfiltered's handling of parsing out requests for pattern matching: case POST(Path(Seg("api" :: "calls" :: name :: Nil))) => this is "englishy" without having you scratch your head. I've also seen case POST(Path("/api/auth")) & Authenticate(user) => which then causes a DB access to happen in a configured implicit value. Now try to reason out why something is not hitting a URL or being denied when you first get into a project. Unless there's someone to explain it to you, it just happens like "magic." TL;DR How much magic do you want to deal with?
- bad_user 13y agoYour example is a sort of strawman argument, probably constructed without you being aware of it. "2.days.from_now" is indeed not free of side-effects, however "now" is a function that depends on the computer's internal clock and is generally understood what it does, the clock being a sort of global state that mutates and is generally available, whereas "2.days.from_last_update" implies usage of local mutable state, passed implicitly and highly dependent on the context you're in. Also, this example is simply wrong ... case POST(Path("/api/auth")) & Authenticate(user) => It's wrong, because this is a route matcher, so if the user is not authenticated, the server would throw an HTTP 404 Not Found status. HTTP 404 Not Found is not meant to be thrown in case the user is not authenticated. There are more relevant, more correct status codes for that, like 401 Unauthorized or 403 Forbidden, or heck, in case of classic websites, a 302 redirect to a login page is in order. So you're basically giving broken examples and calling them "magic", but the examples are obviously broken, the first one in terms of API design, the second one in terms of functionality. I really do understand your hint. But the examples you're giving are bad because they rely on totally non-obvious mutable state that's passed implicitly. This is indeed "magic", however it has nothing to do with syntactic sugar. Btw, in Scala 2.10, thanks to String interpolation, you can also construct route-matchers such as this on [1]: case POST(p"/api/calls/$name/") => Doesn't work by default, you really have to build your own stuff for this to work (see the linked example). Or if you want to throw in regular expressions, you can either do this: case POST(p"/api/calls/${Integer(id)}/") => Or you can have like a mini-DSL with regular expressions built-in: case POST(p"/api/calls/$id<\d+>/?") => // note the optional ending slash Yeah, you can do this. And it's certainly much nicer to me, more flexible and you can also make it faster than pattern-matching on Lists, as in your Unfiltered example. Is this magic? I don't see a local, mutable and implicitly-passed context, so for me it doesn't qualify. Also, whenever I see "2.days" or "4.kilobytes" in Scala code, it's certainly nicer than seeing "172800 /* 2 days in secs /" or "4096 / 4 kb */". Given that these are statically type-checked extension functions that do not modify the original Int type and that do not rely on some mutable local state passed implicitly, is this magic? My IDE doesn't think so. [1] https://github.com/alexandru/shifter/blob/master/web-api/src/test/scala/shifter/web/api/mvc/PathMatcherSuite.scala https://github.com/alexandru/shifter/blob/master/web-api/src...
- ubernostrum 13y agoYears ago I got into an argument about these sorts of "beautiful" and "intuitive" APIs: http://www.reddit.com/r/programming/comments/21pnl/just_say_no_to_ruby_on_rails/c21rwo http://www.reddit.com/r/programming/comments/21pnl/just_say_... I still do not have good answers to the questions I asked in that first comment.
- mpartel 13y agoOne possible answer: static typing + autocompletion. Autocompletion clearly show what you can and can't chain, but admittedly it helps a little less when the DSL asks for a parameter of some type and you don't know how to start building one. Perhaps one way to evaluate the learning curve of an API is to count how many non-standard types appear in the signatures of its methods, excluding the `this` parameter.
- tizoc 13y agoFrom where is that? This is how it works in C# (and .NET in general) DateTime.Now.AddDays(-2) Not wanting to overload integers with calendar functionality doesn't mean you have to make it so cumbersome. Edit: typo
- usea 13y agoYou can also do: DateTime.Now - TimeSpan.FromDays(2)
- MichaelSalib 13y agoI feel the same way that hamburgler does. For me at least, you java calendar code looks horrible. I'm thinking something more like date.today() - timedelta(days=2)
- matthewmacleod 13y agoNote that this syntax is perfectly achievable in Ruby (w/ActiveSupport) too. The following expressions are equivalent: Time.now - 2.days Time.now.advance(days: -2)
- MichaelSalib 13y agoIf you can get exactly the same benefit, then why pay the cost of overriding behavior of the integer type and dealing with hidden black magic that makes your program harder to reason about?
- steveklabnik 13y agoI'm not sure which example you're talking about, but there's no additional cost in the Rust example. And it's not hidden; it's in the trait definition, which is scoped.
- philwelch 13y agoYou're conflating different things here. `Date.today - DateTime.days(2)` would be just as clear as `2.days.ago` without muddling the semantics of integers.