Hi Christopher,

2013/6/23 Christopher Deckers <[email protected]>

> Hi Lukas,
>
> While not very active, I did keep an eye on this discussion, and I too
> found your answer to be very valuable. I am glad to see it making it
> somewhere in the manual.
>

Thanks for joining again. You have mentioned some notable aspects. I'll
respond to your other very interesting mail about long-term strategies
later.


> Languages have reserved keywords, so mapping a language to another is
> likely to clash on some reserved keywords. The amount of clash depends on
> the languages that we consider and tricks we can apply. One consideration
> is about the target languages: should we have the same considerations for
> jOOQ used in Java and jOOQ used in say Scala? I will use "Scala" as a
> generic way of saying "other languages" throughout the discussion. Of
> course I understand that jOOQ's primary target is Java, but I am curious.
>

Yes, we should, even if they're only secondary influences. But jOOQ should
be as Scala and Groovy interoperable as possible.

The only conflict I had with Scala so far was the "val" reserved word,
which I solved by duplicating "DSL.val()" into "DSL.value()" for our Scala
friends.

Note that in the worst case, Scala offers quoting using backticks. I.e.
DSL.`val`() is a possible way to access a Java method that would otherwise
not be accessible in Scala. This is viable for "remote" keywords, not for
frequently used ones, such as AND or SELECT, of course.


>  *1. By introducing artificial keywords. Examples*
>>
>> SQL: UPDATE t SET a = 1, b = 2
>> jOOQ: update(t).set(a, 1).set(b, 2)
>>
>  Note that this example also shows missing operator overloading
>> capabilities, where "=" is replaced by ","
>>
>
> Would jOOQ on Scala be able to more closely match such construct if one
> wanted to?
>

Not every operator can be overloaded in Scala. In particular, I think that
these cannot be overoaded: = , == !=, but I'm not 100% sure.
Groovy has hird-wired rules for operator "overloading":
http://groovy.codehaus.org/Operator+Overloading

I had recently found an interesting PhD thesis on Scala's potential of
being a host to internal domain specific languages, like jOOQ:
http://biblion.epfl.ch/EPFL/theses/2011/5007/EPFL_TH5007.pdf

Interestingly, the thesis also internalises SQL, albeit only very
superficially.

Scala 2.10 also offers Macros, but from what I have seen so far, I am not
sure how they can be leveraged. I simply don't understand the current Macro
documentation.


>  SQL: ORDER BY
>> jOOQ: orderBy()
>>
>
> Would jOOQ on Scala be able to more closely match such construct? I guess
> that would mean having ORDER(BY(xxx)) and then BY could be problematic if
> used in other places.
>

Scala's ability to omit parentheses in certain cases will lure you into
thinking that these things will be useful. This topic is dealt with
extensively in the above thesis.

Let's look at your example (pseudo Scala, might not be entirely correct):

================================
object ScalaDSL {
  def BY(Field f) : ByField = ...
  def BY(SortField f) : BySortField = ...
}

trait SelectOrderByStep {
  def ORDER(ByField f) = ...
}
================================

A lot of types like ByField and BySortField would be introduced. These
types are only used for DSL syntax implementation. They have no other
meaning but can be reused among clauses, e.g. PARTITION BY, GROUP BY.

Another option to implement "ORDER BY field":

================================
trait SelectOrderStep {
  def ORDER : SelectOrderByStep;
}

trait SelectOrderByStep {
  def BY(Field f) : ...
  def BY(SortField f) : ...
}
================================

This becomes a bit different with "three-letter" keyword combinations.
Let's take Oracle's ORDER SIBLINGS BY, for instance. The above would then
be enhanced to:

================================
trait SelectOrderStep {
  def ORDER : SelectOrderByStep;
  def ORDER(SIBLINGS s) : SelectOrderByStep;
}

object SIBLINGS {}

trait SelectOrderByStep {
  def BY(Field f) : ...
  def BY(SortField f) : ...
}
================================

But the problem here is the fact that introducing a SIBLINGS syntactic
element will also introduce ambiguities when writing

================================
ORDER SIBLINGS BY f

// is the above:
ORDER().SIBLINGS().BY(f)

// or is it:
ORDER(SIBLINGS).BY(f)

// apparently, Scala's lexer doesn't know, and the compiler cannot
// disambiguate this, according to the language reference. Disambiguation:
(ORDER SIBLINGS) BY f
================================

Having exprimented already for a couple of hours (and having read that
thesis), I don't think that a truly satisfiable solution where all nasty
dots and parentheses can be omitted, is possible in an API that makes heavy
use of overloading, such as jOOQ's. The rules are too complex to handle in
productive code, and if you don't handle them, you will resort to code that
is worse to read, write and maintain than jOOQ's, i.e. ORDER(BY(f)) or
ORDER().BY(f) or (ORDER SIBLINGS) BY f.

The worst thing about these techniques is the fact that, *IF* you get
something wrong, syntactically, enjoy finding your mistake if you're
running a SQL statement like this one:
http://blog.jooq.org/2011/11/14/jooq-meta-a-hard-core-sql-proof-of-concept

Feel free to experiment with Scala yourself, though. I'm sure I haven't
seen it all, yet :-)


>  *6. By using descriptive methods, or a comma*
>>
>> Most SQL operators have to be mapped to descriptive method names in Java:
>>
>> SQL: =
>> jOOQ: equal(), eq()
>>
>
> What is the rule with verbs? Should it be 3rd person, like "equals()" (if
> there were no collisions with Java's equals)?
>

eq() elegantly solves this problem :-)

As you've correctly guessed, collision with Java's equals() was the problem
here. If verbs *had* to be chosen, I would probably have to change
greaterThan() into isGreaterThan(), choosing IS to be consistent with IS
NULL, IS DISTINCT FROM, etc. Thus, isEqual() would be the "SQL way" to
write out "="

That might be a change worth considering for jOOQ 4.0, in a greater context.


>  SQL: <>
>> jOOQ: notEqual(), ne()
>>
>
> Would jOOQ on Scala be able to more closely match such construct?
>

Yes. See my other mail or the manual:
http://www.jooq.org/doc/3.0/manual/sql-building/scala-sql-building


> *7. That cannot be worked around*
>>
>> This is what has been keeping me from implementing CTE so far.
>>
>> SQL: WITH a(x, y) AS (SELECT 1, 2) SELECT a.x, a.y FROM a
>>
>
> What is the problem with the above expression?
>

The problem is that a is not well-defined in SELECT a.x, a.y or in FROM a.
The above would have to be written as:

Table<?> a = select(val(1), val(2)).asTable("a", "x", "y");

with(a)
.select(a.field("x"), a.field("y"))
.from(a);

It would work, of course. But it wouldn't feel exactly like SQL. And you
would lose all typesafety.


>  *Discussion*
>>
>> a) by using synonyms
>>
>
> This is the worst suggestion in my view.
>

Yes, I agree with you. :-)

As an excuse... at the time I implemented this, I wasn't aware of the fact
that jOOQ might eventually go that far. I think, decode() was in there
since version 1.0. At least, it's contained in the first Maven-published
version:
http://grepcode.com/file/repo1.maven.org/maven2/org.jooq/jooq/1.5.7/org/jooq/Field.java#Field.decode%28org.jooq.Field%2Corg.jooq.Field%2Corg.jooq.Field%5B%5D%29

So, let's consider decode() an early "API blunder"

 b) by appending "disambiguators" such as case_ or case$ or case
>>
>
> I don't mind hard rules, like "any keyword that may clash with Java
> keyword is going to be suffixed with '_'". I prefer suffix, because code
> completion would work when I start typing "case".
>

Agreed on the suffix. But I'd really like to avoid this as long as
possible. It's quite an "ugly" solution for something as frequent as a CASE
expression.


> c) by introducing artificial spelling, such as casë, casǝ, casɇ ;-)
>>
>
> OK, this *IS* the worst suggestion :)
> You forgot \uFF43\uFF41\uFF53\uFF45: case
>

Great! I was looking for those letters, just didn't find them. Hey, you
only need the e, as in case. That way, IDE auto-completion can still help
the poor developers, in case they don't remember FF45 ;-)

d) by changing the API to be all-uppercase: SELECT(), CASE(), ORDER_BY()
>>
>
> My initial reaction was "ouch, this is ugly Java", but I do write SQL all
> caps, so having the DSL part be all caps to map SQL is really not that bad.
>

Yes, and it would stress the fact that jOOQ is really actually SQL embedded
in Java, more typesafely and with more features than SQLJ.

e) by changing the API to be camel-case with an upper-case initial letter:
>> Select(), Case(), OrderBy()
>>
>
> This is odd, because it is neither the Java convention nor SQL.
>

I have seen it once or twice in a SQL Server / .NET context, although T-SQL
uses UPPERCASE in their conventions:
http://msdn.microsoft.com/en-us/library/ms177563.aspx

But in .NET, method names are often PascalCased:
http://msdn.microsoft.com/en-us/library/ms229043.aspx

It wouldn't be the worst solution, but still odd.


>  d) and e) are massive changes.
>>
>
> Apart from being an incompatible API, what is the complexity? User manual
> mainly?
>

Massive in the amount of work for me :-) (and for users if it wasn't
backwards-compatible)
You're right, there isn't much complexity. It would simply mean:

- Creating a code-generator that generates delegate methods for one syntax,
delegating to the other
- Creating a section in the manual explaining that both are possible
- Creating some indicative integration tests

If it can be guaranteed, that for every orderBy(), there shall also be an
ORDER_BY(), the above would be sufficient. And using our new annotations
(those for the BNF), it will be easy to discover, which methods need to be
duplicated.

If people wanted to reduce their jOOQ binary footprint, they could rebuild
jOOQ, omitting the duplication.

Of course, such a strategy would also indicate, that your suggestion is the
only viable way to implement case_(), else_(), for_() in the camelCase API.

Any other ideas?
>>
>
> Apart from silly ideas like "cASE", not really :)
>

caze? elze?
ca$e? el$e?
esac? esle?

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to