Closed nrinaudo closed 3 years ago
Just to make this clear, here's how I'd imagine the syntax to work:
val jodaFormat: org.joda.time.format.DateTimeFormatter = joda"yyyy-MM-dd'T'HH:mm:ssV"
val java8Format: java.time.format.DateTimeFormatter = date"yyyy-MM-dd'T'HH:mm:ssV"
val url: java.net.URL = url"https://github.com"
val uri: java.net.URI = uri"https://github.com"
Mentioned on twitter:
These would be handy to have, but it would also be nice to have a non-side-effecting URI/URL. The java.net one makes a dns call on instantiation. Rapture version may be preferred.
It might be worthwhile having Contextual provide just the data representations of these things, with no interesting methods implemented, and have the actual interesting stuff (e.g. an HTTP POST method on a URL) provided as extension methods in other libraries.
@ShaneDelmore is that true though? I thought it was during comparison, since two URLs are expected to be equal if they resolve to the same canonical IP / path, does it really also happen at creation time?
@ShaneDelmore after looking around a bit, it does appear to only be when calling either equals or hashCode, and only in the case of URL - URI is relatively sane.
I would vote against dedicated types, at least in this context. The idea behind this issue was to provide standard "literal" syntax for common types - URL and URI are common types that people often have to interact with.
A sane URL implementation is of course always a good idea, but I don't think it's contextual's job.
Not really the point of the discussion, but I'm pretty sure two URLs whose domains resolve to the same host IP should not be considered equal, as HTTP Host
parameter gets passed with the request, and allows the same server to process it entirely differently for each case...
Anyway, how about we create a separate project called, say contextual-representations
(unless anyone can suggest a better name), that acts as a library of typed representations of various datatypes, constructed from interpolated strings.
I would imagine these would be simple and numerous. Anything complex, like XML, would quite quickly get moved out into its own project.
Any objections?
@propensive regarding the URL issue: you're right, it shouldn't. Unfortunately, it is. See this stackovervlow answer, for example.
Regarding contextual-representations
, I'm fine with the general concept, but you'll need more than just one library, right? Or at least multiple modules that can be imported independently. Take the example of java8 DateTimeFormatter
- this cannot be in the "main" representations module, since it has a hard dependency on java8, which is not yet an assumption you can safely make.
I was thinking along the same lines as @nrinaudo - maybe good if these representations were organized by the dependencies they need?
@rintcius Precisely what I had in mind:
contextual-core
: support for all types in the Java and Scala stdlibs, all other modules depend on itcontextual-java8
: java8 specific types (date / time, mostly)contextual-jodatime
: joda time, for people stuck in java < 8contextual-xml
: for the "standard" Scala XML library@nrinaudo I didn't even follow your SO link... I believe it, and it was too depressing! ;)
Anyway, regarding the main question: maybe, maybe not... You're definitely right that we wouldn't want to have people get, say, time dependencies on their classpath if they only wanted to parse an IP address, though you equally don't want to have to add six tiny dependencies to your build just to support six different datatypes you happen to be using. So @rintcius's suggestion (just this second seconded by @nrinaudo!) sounds reasonable.
That said, I'm not sure we need Java8 or JodaTime dependencies. If we parse a date, we can represent it by day, month and year (let's assume Gregorian only, for now), as a triple of Int
s. I don't think we need an external parser to do the parsing (it certainly wouldn't be the most complex parser we would have). If someone wants to use the contextual-representations
version of Date
, then they write a converter to their favourite time library, and that becomes the new dependency...
Though I'm not adamant about any of this yet. Given that we're starting almost from scratch, I think we can begin by putting everything we do into a single contextual-representations
library, with the view to splitting it up when it needs it, prior to a "first release" version.
There have been some suggestions already, but maybe we could start brainstorming all the different things we might want to represent?
@propensive I'm wondering if we're talking about the same thing here - both are good and fit specific use cases, but my intention with this issue was not for Contextual to create new data types, but to provide literal syntax for existing ones.
Let me take the example of dates. I work with a lot of client data, which is always timestamped. I use either joda (if java < 8) or java date time (if java 8+) to deal with them, but always end up having to define custom formats - normal people don't apparently care much for ISO 8601. What I'd love to do is declare my formats in a way that would be checked at compile time:
val customFormat: DateTimeFormatter = joda"yyyy-MM-dd'T'mm:hh:ssZ"
In this context, a custom representation of date or times doesn't interest me - I already have access to a pretty good one. I just want literal syntax for types that already exist.
Having bespoke types for common concepts, and Contextual "connectors" for them, is also a good idea, but a completely different one. Maybe we should split this issue in two and make it clear which is which, since there appears to be some confusion (at least on my end)?
W.r.t. ideas for representations, https://github.com/fthomas/refined (and https://github.com/fthomas/refined/wiki/Built-with-refined) may be a good source.
Is joda still preferred over threetenbp? Incidentally all of them were written by the same guy.
I had never even heard of threetenbp - thanks!
Can we cross compile the date format interpolator so that it includes threetenbp on Java<8. The difference in package naming probably makes that non trivial
@gabrieljones well I mean right now there appears to be confusion about whether we want to write our own types or just literal syntax for existing types (which is what you seem to be talking about), so this seems a bit early :)
But yeah, it might require some SBT-fu, but it certainly seems achievable.
@nrinaudo Something would have to be there so we can abort the compile if the format string is invalid.
https://github.com/gabrieljones/DateTimeFormatInterpolator
Here is my initial attempt.
Sorry I've not had time to contribute to this thread as much as I'd like... I'll be back at full pace once this week's over, though. :)
out-of-the-box parser for stdlib data types would be awesome! Support for Instant
would be :100:
I will probably put one together, you're welcome to it, but I'm sure you're aware how trivial it is.
Scala and Java both have lots of types that are initialised from a string, where an illegal string will compile but fail at runtime. It'd be great if Contextual could provide standard modules for such types.
I've often felt the need for such a tool for:
java.net.URL
java.net.URI
I'm sure there are a lot commonly used types out there that would benefit from a literal syntax.
Happy to lend a hand or even write most of these, but if you feel this is a good idea, the structure needs to come from you - do you want that to be a completely separate library that depends on Contextual? Standard Contextual modules that live in this repository?