- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Draft SIP: Curly import for more authentic DSLs
Thu, 2009-03-26, 11:06
Following up a discussion in the "Scala" forum, I would like to submit the
following draft preSIP:
http://web.me.com/obua/sip_curly_import/sip.xhtml
Best,
Steven Obua
Thu, 2009-03-26, 13:17
#2
Re: Draft SIP: Curly import for more authentic DSLs
I tried to code the myAssert example in Scala, and it does not work, you are
right.
It seems that "()" is not the same as the "Unit" type (which was what I
thought).
If you change the type definition of the argument of myAssert from "() =>
Boolean" to "Unit => Boolean" then everything works as expected. I changed
that in the preSIP, thanks a lot for your input!
The usefulness of the myAssert example is that it demonstrates how the
"curly import" feature makes superfluous another feature ("by-name"
parameters) which is more of an exceptional case rather than a general
principle. When such a thing happens, this is often a good sign that the
new feature is a good thing and not just something you stick into your
language just to cover an isolated problem (I would argue that "by-name"
parameters fell into that trap...)
Concerning type checking I think one could follow the philosophy of Monads:
just expand the stuff, and try to type check the result. For DSLs you would
normally specify the type of the imported parameter in the method signature,
like in the myAssert example. From the definition of myAssert it follows
that the type of the import parameter must be "Unit".
Johannes Rudolph-2 wrote:
>
> I don't get the assert example. Neither its usefulness nor how it
> applies to your specification.
>
> Following your specification
>
> myAssert {: 5 > 3 }
>
> should be expanded into
>
> myAssert { context => import context._
> 5 > 3
> }
>
> The parameter would be of type _ => Boolean but myAssert expects () =>
> Boolean. So how should that work and what would be the improvement
> over the version without Curly import?
>
> How does the feature play along with type-checking? Do you need to
> specify the type of the imported parameter and how would that be done?
>
> Johannes
>
> -----------------------------------------------
> Johannes Rudolph
> http://virtual-void.net
>
>
>
> On Thu, Mar 26, 2009 at 11:06 AM, Steven Obua wrote:
>>
>> Following up a discussion in the "Scala" forum, I would like to submit
>> the
>> following draft preSIP:
>>
>> http://web.me.com/obua/sip_curly_import/sip.xhtml
>>
>> Best,
>>
>> Steven Obua
>> --
>> View this message in context:
>> http://www.nabble.com/Draft-SIP%3A-Curly-import-for-more-authentic-DSLs-...
>> Sent from the Scala - Debate mailing list archive at Nabble.com.
>>
>>
>
>
Thu, 2009-03-26, 13:57
#3
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 1:13 PM, Steven Obua wrote:
>
>
> The usefulness of the myAssert example is that it demonstrates how the
> "curly import" feature makes superfluous another feature ("by-name"
> parameters) which is more of an exceptional case rather than a general
> principle.
I'm really not sure I follow this, are you saying that your feature
could replace by-name?
If so I don't agree with that.
I think that by-name itself is largely redunant and should simply be
(Unit) => T. The DSL use of by name should be syntactic sugar only
IMO
There are lots of little cases that byname covers (I and others have
raised this type of thing before ). In particular the BNF covers
blocks that must have a return expression. This particular syntactic
feature means that () => T is very much different than => T in terms
of evaluation.
As an aside if such a syntax was to be useful I think it should be
driven from both a use site and declaration perspectives. It would be
nice if the :
context =>
implicit val icontext = context
boilerplate could be removed. I.e. it would be better to have the
declaration mention this (implicit T) => X or similar.
As a further aside, I think by name is anything but an exceptional
case, but obviously ymhv.
Thu, 2009-03-26, 14:17
#4
Re: Draft SIP: Curly import for more authentic DSLs
Chris Twiner wrote:
>
> I'm really not sure I follow this, are you saying that your feature
> could replace by-name?
>
> If so I don't agree with that.
>
> I think that by-name itself is largely redunant and should simply be
> (Unit) => T. The DSL use of by name should be syntactic sugar only
> IMO
>
>
So is this rant your opinion? If so, we do agree! I am relatively new to
Scala, so I don't know all the ways that by-name parameters are useful; I
don't like the idea of introducing a new type => T to capture laziness. Unit
=> T already does that! So yes, curly import could replace by-name in my
opinion.
But I am not saying that it should replace by-name at this stage of Scala;
Scala is striving for industrial-strength, so removing something like
by-name is not an option. My purpose in bringing up the by-name example was
to highlight the generality of curly import despite its simplicity.
Thu, 2009-03-26, 15:07
#5
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 2:15 PM, Steven Obua wrote:
>
>
>
> Chris Twiner wrote:
>>
>> I'm really not sure I follow this, are you saying that your feature
>> could replace by-name?
>>
>> If so I don't agree with that.
>>
>> I think that by-name itself is largely redunant and should simply be
>> (Unit) => T. The DSL use of by name should be syntactic sugar only
>> IMO
>>
>>
>
> So is this rant your opinion? If so, we do agree! I am relatively new to
> Scala, so I don't know all the ways that by-name parameters are useful; I
> don't like the idea of introducing a new type => T to capture laziness. Unit
> => T already does that! So yes, curly import could replace by-name in my
> opinion.
IMO yes I think they overlap too much to offer benefit, however also
IMO it should be dictated by declaration not by use site. However I
also recognise that by-names have different evaluation semantics,
again I don't think these offer much.
> But I am not saying that it should replace by-name at this stage of Scala;
> Scala is striving for industrial-strength, so removing something like
> by-name is not an option. My purpose in bringing up the by-name example was
> to highlight the generality of curly import despite its simplicity.
Agreed its in no way possible to replace it. I'd also add that if
such a syntax were accepted it would actually allow for the implicit
declarations, given that the object itslef could simply define it.
Just to restate, I'm not against the proposal, I think that something
like this is required.
Thu, 2009-03-26, 18:37
#6
Re: Draft SIP: Curly import for more authentic DSLs
What do you expect in this situation:
def f( ff : (SameType,SameType) => Other) = {...}
f {:.....}
Is it compilation error?
Thu, 2009-03-26, 18:47
#7
Re: Draft SIP: Curly import for more authentic DSLs
I just saw that the word "Draft" is bound in the SIP process.
So the title of my posting should rather be "PreSIP: Curly import for more
authentic DSLs".
Steven Obua wrote:
>
> Following up a discussion in the "Scala" forum, I would like to submit the
> following draft preSIP:
>
> http://web.me.com/obua/sip_curly_import/sip.xhtml
>
> Best,
>
> Steven Obua
>
Thu, 2009-03-26, 18:47
#8
Re: Draft SIP: Curly import for more authentic DSLs
I would not consider this a compilation error; the type of your CONTEXT
variable is Tuple2.
So everything that Tuple2 has to offer should be in context now, like "_1"
or "_2".
Vladimir Kirichenko-2 wrote:
>
> What do you expect in this situation:
>
> def f( ff : (SameType,SameType) => Other) = {...}
>
> f {:.....}
>
> Is it compilation error?
>
Thu, 2009-03-26, 18:57
#9
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 6:28 PM, Vladimir Kirichenko
wrote:
> What do you expect in this situation:
>
> def f( ff : (SameType,SameType) => Other) = {...}
>
> f {:.....}
>
> Is it compilation error?
>
I'd hope so, anything else would be very strange (such as importing
all of the parameters).
Thu, 2009-03-26, 18:57
#10
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 5:49 PM, Chris Twiner wrote:
> (a,x) => T != Tuple2[A,X] => T
Yes, but it's not immediately obvious to me why that should matter
(other than that the pre-SIP needs to be updated to accommodate the
distinction).
I have to confess that I really quite like this proposal, tho' I also
suspect it doesn't offer quite enough to warrant the effort ... more
and more compelling use cases might help.
Cheers,
Miles
Thu, 2009-03-26, 19:07
#11
Re: Draft SIP: Curly import for more authentic DSLs
(a,x) => T != Tuple2[A,X] => T
Although there does seem to be movement in that direction for 2.8.0
On Thu, Mar 26, 2009 at 6:43 PM, Steven Obua wrote:
>
> I would not consider this a compilation error; the type of your CONTEXT
> variable is Tuple2.
> So everything that Tuple2 has to offer should be in context now, like "_1"
> or "_2".
>
>
> Vladimir Kirichenko-2 wrote:
>>
>> What do you expect in this situation:
>>
>> def f( ff : (SameType,SameType) => Other) = {...}
>>
>> f {:.....}
>>
>> Is it compilation error?
>>
>> --
>> Best Regards,
>> Vladimir Kirichenko
>>
>>
>
> --
> View this message in context: http://www.nabble.com/Draft-SIP%3A-Curly-import-for-more-authentic-DSLs-...
> Sent from the Scala - Debate mailing list archive at Nabble.com.
>
>
Thu, 2009-03-26, 19:07
#12
Re: Draft SIP: Curly import for more authentic DSLs
As I said in my previous posting, I really don't mind using Tuple2 (or Unit,
for that matter) as a context type. But I can understand people who want
more safety.
In Java I would propose something like "oh, only context classes that are
derived from that empty interface CurlyImportContext are allowed, everything
else gives a compile time error". Is there something similar in Scala ? Any
opinions? An argument against it could be that then the implementation of
the feature might become more complicated, because type checking cannot be
delegated any more to after the rewriting of {: }. But because of the
slightly changed semantics it is maybe anyway more difficult to implement
than just employing simple rewriting.
I must confess I dont know the distinction between (A,B) => C and Tuple2[A,
B] => C. Before your post I didn't even know that I could write (A, B). I
looked it up in the scala reference manual, section 3.2.5, and there it says
that (A, B) is just a shortcut for Tuple2[A, B].
Chris Twiner wrote:
>
> On Thu, Mar 26, 2009 at 6:28 PM, Vladimir Kirichenko
> wrote:
>> What do you expect in this situation:
>>
>> def f( ff : (SameType,SameType) => Other) = {...}
>>
>> f {:.....}
>>
>> Is it compilation error?
>>
>
> I'd hope so, anything else would be very strange (such as importing
> all of the parameters).
>
>
Thu, 2009-03-26, 19:17
#13
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 6:53 PM, Miles Sabin wrote:
> On Thu, Mar 26, 2009 at 5:49 PM, Chris Twiner wrote:
>> (a,x) => T != Tuple2[A,X] => T
>
> Yes, but it's not immediately obvious to me why that should matter
> (other than that the pre-SIP needs to be updated to accommodate the
> distinction).
As I say, hopefully automatic "curry/uncurry" will be in 2.8.0.
> I have to confess that I really quite like this proposal, tho' I also
> suspect it doesn't offer quite enough to warrant the effort ... more
> and more compelling use cases might help.
For me the best use case is that I can dump using dynamicvariables, as
this would allow threading of implicit defs instead. The same could
be said for STM etc approaches i.e. make sure that the parameters are
explicit not hidden on the stack / thread somewhere.
Thu, 2009-03-26, 19:27
#14
Re: Draft SIP: Curly import for more authentic DSLs
> I must confess I dont know the distinction between (A,B) => C and Tuple2[A,
> B] => C. Before your post I didn't even know that I could write (A, B). I
> looked it up in the scala reference manual, section 3.2.5, and there it says
> that (A, B) is just a shortcut for Tuple2[A, B].
Parameters. The point was about the import conflict: two
symbols(contexts) with the same type, or different types but with
similar members.
class A {
def or..
}
class B {
def or..
}
def f( ff : (A,B) => Other) = {...}
f {:.....}
?
Thu, 2009-03-26, 19:57
#15
Re: Draft SIP: Curly import for more authentic DSLs
On Thu, Mar 26, 2009 at 7:05 PM, Steven Obua wrote:
>
> In Java I would propose something like "oh, only context classes that are
> derived from that empty interface CurlyImportContext are allowed, everything
> else gives a compile time error". Is there something similar in Scala ? Any
> opinions?
I personally don't think that this helps in anyway, the simplicity of
expanding {: into the x => import x._ should be enough.
> I must confess I dont know the distinction between (A,B) => C and Tuple2[A,
> B] => C. Before your post I didn't even know that I could write (A, B). I
> looked it up in the scala reference manual, section 3.2.5, and there it says
> that (A, B) is just a shortcut for Tuple2[A, B].
>
(A, B) => C is a function taking two parameters A and B and returning
C. (A, B) however is Tuple2[A, B]. The type for a tuple based
function would be ((A,B)) => C, i.e. one parameter which is a tuple.
I think the safest thing to do is just allow this for one parameter
functions only. Simpler to reason about and to implement, it also
avoids collisions.
Fri, 2009-03-27, 09:47
#16
Re: Draft SIP: Curly import for more authentic DSLs
Chris Twiner wrote:
>
>
> I think the safest thing to do is just allow this for one parameter
> functions only. Simpler to reason about and to implement, it also
> avoids collisions.
>
>
I agree, this whole thing makes only sense for one parameter functions
anyway! I will update the presip to state this explicitly.
Of course, curried functions should pose no problem, i.e. a function f of
type (A => X) => (B => Y) => C should be callable via f {: ... } {: ... }
Fri, 2009-03-27, 13:57
#17
Re: Draft SIP: Curly import for more authentic DSLs
> I agree, this whole thing makes only sense for one parameter functions
> anyway!
Actually it does not. The whole point was about replacing of (...) =>
construct and parameter reference with import for DSLs. There is no
reasons to think that DSL will use the functions with the only
parameter. This makes sense for all DSLs. One parameter functions are
the particular case. I'm pretty sure that general purpose language
design should avoid to be based on particular cases.
Fri, 2009-03-27, 14:17
#18
Re: Draft SIP: Curly import for more authentic DSLs
I think allowing more than one parameter is not needed for any DSL.
When designing a DSL, you should design it carefully. The point of my
proposal is that you need a kind of "dynamic context" for DSLs. There is
only ONE such context. It may of course vary from situation to situation,
but thats what the "dynamic" is for. If you need two parameters in order to
set up the right context, you should reconsider how to merge these two
parameters into one.
Best,
Steven
Vladimir Kirichenko-2 wrote:
>
>> I agree, this whole thing makes only sense for one parameter functions
>> anyway!
>
> Actually it does not. The whole point was about replacing of (...) =>
> construct and parameter reference with import for DSLs. There is no
> reasons to think that DSL will use the functions with the only
> parameter. This makes sense for all DSLs. One parameter functions are
> the particular case. I'm pretty sure that general purpose language
> design should avoid to be based on particular cases.
>
>
Fri, 2009-03-27, 15:07
#19
Re: Draft SIP: Curly import for more authentic DSLs
Could you please provide some example I could play with? Because of by
provided examples I cant see need of new syntax:
class Theorem
case class Fixed(name:String, t:Theorem) extends Theorem
case class Assumed(prop:String, t:Theorem) extends Theorem
case class Cases(t:Theorem, case1:Theorem,case2:Theorem) extends Theorem
case class Or(case1: String, case2:Theorem) extends Theorem
case class Fact(case1: String) extends Theorem
class Context {
def fix(name : String) (cont : Context => Theorem) : Theorem =
Fixed(name, cont(new Context()))
def assume(prop : String) (cont : Context => Theorem) : Theorem =
Assumed(prop, cont(new Context()))
def cases(th : Theorem)(cont1 : Context => Theorem)(cont2 :
Context => Theorem) : Theorem = Cases(th, cont1(new Context()),
cont2(new Context()))
def or (case1 : Theorem, case2 : String) : Theorem = Or(case2, case1)
def or (case1 : String, case2 : Theorem) : Theorem = Or(case1, case2)
def fact(prop : String) : Theorem = Fact(prop)
}
class Context2 {
def fix(name : String) (t : => Theorem): Theorem = Fixed(name, t)
def assume(prop : String) (t : => Theorem): Theorem = Assumed(prop, t)
def cases(th : Theorem)(t1 : => Theorem)(t2 : => Theorem): Theorem
= Cases(th, t1, t2)
def or (case1 : Theorem, case2 : String) : Theorem = Or(case2, case1)
def or (case1 : String, case2 : Theorem) : Theorem = Or(case1, case2)
def fact(prop : String) : Theorem = Fact(prop)
}
object Do extends Application {
val u = new Context()
val t = u.fix ("A") {
u => u.fix ("B") {
u => u.fix ("C") {
u => u.assume ("(A ∨ B) ∨ C") {
u => u.cases (u.fact("(A ∨ B) ∨ C"))
{
u => u.cases (u.fact ("A ∨ B"))
{
u => u.or ("B", u.or ("C", u.fact("A")))
} {
u => u.or (u.fact("B"), "C ∨ A")
}
} {
u => u.or ("B", u.or(u.fact("C"), "A"))
}}}}}
println(t)
val c2 = new Context2();
import c2._
val t2 = fix ("A") {
fix ("B") {
fix ("C") {
assume ("(A ∨ B) ∨ C") {
cases (u.fact("(A ∨ B) ∨ C"))
{
cases (u.fact ("A ∨ B"))
{
or ("B", or ("C", fact("A")))
} {
or (fact("B"), "C ∨ A")
}
} {
or ("B", or(u.fact("C"), "A"))
}}}}}
println(t2)
}
Output:
Fixed(A,Fixed(B,Fixed(C,Assumed((A ∨ B) ∨ C,Cases(Fact((A ∨ B) ∨
C),Cases(Fact(A ∨ B),Or(B,Or(C,Fact(A))),Or(C ∨
A,Fact(B))),Or(B,Or(A,Fact(C))))))))
Fixed(A,Fixed(B,Fixed(C,Assumed((A ∨ B) ∨ C,Cases(Fact((A ∨ B) ∨
C),Cases(Fact(A ∨ B),Or(B,Or(C,Fact(A))),Or(C ∨
A,Fact(B))),Or(B,Or(A,Fact(C))))))))
Fri, 2009-03-27, 15:27
#20
Re: Draft SIP: Curly import for more authentic DSLs
What you did is to remove the dependency of Context.or, Context.assume etc.
on Context. You did this by introducing
a global import c2._, assuming that "or", "assume" etc are "static Class
functions". Sadly, these functions really do depend on the specific context
which changes throughout the computation (this is not visible in my example
code because I have not given the implementations of the Context
methods);-).
If you like another example, I am currently trying to work another example
into the presip, I'll let you know once it is there.
Vladimir Kirichenko-2 wrote:
>
> Could you please provide some example I could play with? Because of by
> provided examples I cant see need of new syntax:
>
> class Theorem
> case class Fixed(name:String, t:Theorem) extends Theorem
> case class Assumed(prop:String, t:Theorem) extends Theorem
> case class Cases(t:Theorem, case1:Theorem,case2:Theorem) extends Theorem
> case class Or(case1: String, case2:Theorem) extends Theorem
> case class Fact(case1: String) extends Theorem
>
>
> class Context {
>
> def fix(name : String) (cont : Context => Theorem) : Theorem =
> Fixed(name, cont(new Context()))
>
> def assume(prop : String) (cont : Context => Theorem) : Theorem =
> Assumed(prop, cont(new Context()))
>
> def cases(th : Theorem)(cont1 : Context => Theorem)(cont2 :
> Context => Theorem) : Theorem = Cases(th, cont1(new Context()),
> cont2(new Context()))
>
> def or (case1 : Theorem, case2 : String) : Theorem = Or(case2, case1)
>
> def or (case1 : String, case2 : Theorem) : Theorem = Or(case1, case2)
>
> def fact(prop : String) : Theorem = Fact(prop)
>
> }
>
>
> class Context2 {
>
> def fix(name : String) (t : => Theorem): Theorem = Fixed(name, t)
>
> def assume(prop : String) (t : => Theorem): Theorem = Assumed(prop, t)
>
> def cases(th : Theorem)(t1 : => Theorem)(t2 : => Theorem): Theorem
> = Cases(th, t1, t2)
>
> def or (case1 : Theorem, case2 : String) : Theorem = Or(case2, case1)
>
> def or (case1 : String, case2 : Theorem) : Theorem = Or(case1, case2)
>
> def fact(prop : String) : Theorem = Fact(prop)
>
> }
>
> object Do extends Application {
> val u = new Context()
> val t = u.fix ("A") {
> u => u.fix ("B") {
> u => u.fix ("C") {
> u => u.assume ("(A ∨ B) ∨ C") {
> u => u.cases (u.fact("(A ∨ B) ∨ C"))
> {
> u => u.cases (u.fact ("A ∨ B"))
> {
> u => u.or ("B", u.or ("C", u.fact("A")))
> } {
> u => u.or (u.fact("B"), "C ∨ A")
> }
> } {
> u => u.or ("B", u.or(u.fact("C"), "A"))
> }}}}}
> println(t)
>
> val c2 = new Context2();
> import c2._
>
> val t2 = fix ("A") {
> fix ("B") {
> fix ("C") {
> assume ("(A ∨ B) ∨ C") {
> cases (u.fact("(A ∨ B) ∨ C"))
> {
> cases (u.fact ("A ∨ B"))
> {
> or ("B", or ("C", fact("A")))
> } {
> or (fact("B"), "C ∨ A")
> }
> } {
> or ("B", or(u.fact("C"), "A"))
> }}}}}
>
> println(t2)
> }
>
>
> Output:
>
> Fixed(A,Fixed(B,Fixed(C,Assumed((A ∨ B) ∨ C,Cases(Fact((A ∨ B) ∨
> C),Cases(Fact(A ∨ B),Or(B,Or(C,Fact(A))),Or(C ∨
> A,Fact(B))),Or(B,Or(A,Fact(C))))))))
> Fixed(A,Fixed(B,Fixed(C,Assumed((A ∨ B) ∨ C,Cases(Fact((A ∨ B) ∨
> C),Cases(Fact(A ∨ B),Or(B,Or(C,Fact(A))),Or(C ∨
> A,Fact(B))),Or(B,Or(A,Fact(C))))))))
>
>
>
>
Fri, 2009-03-27, 15:37
#21
Re: Draft SIP: Curly import for more authentic DSLs
On Fri, Mar 27, 2009 at 4:22 PM, Steven Obua wrote:
>
> What you did is to remove the dependency of Context.or, Context.assume etc.
> on Context. You did this by introducing
> a global import c2._, assuming that "or", "assume" etc are "static Class
> functions".
They are not static. It's an instance import.
> Sadly, these functions really do depend on the specific context
> which changes throughout the computation (this is not visible in my example
> code because I have not given the implementations of the Context
> methods);-).
Yep. And the evaluation result based on declarations is the same as we
see in outputs.
> If you like another example, I am currently trying to work another example
> into the presip, I'll let you know once it is there.
ok.
Fri, 2009-03-27, 15:47
#22
Re: Draft SIP: Curly import for more authentic DSLs
Vladimir Kirichenko-2 wrote:
>
> On Fri, Mar 27, 2009 at 4:22 PM, Steven Obua wrote:
>>
>> What you did is to remove the dependency of Context.or, Context.assume
>> etc.
>> on Context. You did this by introducing
>> a global import c2._, assuming that "or", "assume" etc are "static Class
>> functions".
>
> They are not static. It's an instance import.
>
>
From a purely syntactic point of view, sure. That's why I used "quotes".
But you assume that all of the following code depends on this particular
instance of a Context, which it does not.
Fri, 2009-03-27, 15:57
#23
Re: Draft SIP: Curly import for more authentic DSLs
On Fri, Mar 27, 2009 at 3:31 PM, Vladimir Kirichenko
wrote:
> On Fri, Mar 27, 2009 at 4:22 PM, Steven Obua wrote:
>>
>> What you did is to remove the dependency of Context.or, Context.assume etc.
>> on Context. You did this by introducing
>> a global import c2._, assuming that "or", "assume" etc are "static Class
>> functions".
>
> They are not static. It's an instance import.
It is worth noting that
val c2 = new Context2();
import c2._
is exactly the boilerplate being referred to, or from your previous (I
find terrible to read as well :-) ) example:
val t = u.fix ("A") {
u => u.fix ("B") {
u => u.fix ("C") {
u => u.assume ("(A ∨ B) ∨ C") {
u => u.cases (u.fact("(A ∨ B) ∨ C"))
{
u => u.cases (u.fact ("A ∨ B"))
{
u => u.or ("B", u.or ("C", u.fact("A")))
} {
u => u.or (u.fact("B"), "C ∨ A")
}
} {
u => u.or ("B", u.or(u.fact("C"), "A"))
}}}}}
EACH of those u => 's could be a different context , your actual demo
implementation is limited in that regard and could supply many
different contexts throughout the chain for each of these functions.
Irrespective it is far easier to read your second block of code, all
this syntax proposal adds is that the given or, cases or fact can vary
at each point in the chain.
Fri, 2009-03-27, 16:17
#24
Re: Draft SIP: Curly import for more authentic DSLs
> Irrespective it is far easier to read your second block of code, all
> this syntax proposal adds is that the given or, cases or fact can vary
> at each point in the chain.
I understand that. I'm just not sure that it's an only way to
implement DSL like this. That's why I'm asking for the real example. I
want to try to implement it another way (different than "context
passing") to reach the same DSL syntax.
Fri, 2009-03-27, 16:37
#25
Re: Draft SIP: Curly import for more authentic DSLs
> I understand that. I'm just not sure that it's an only way to
> implement DSL like this. That's why I'm asking for the real example. I
> want to try to implement it another way (different than "context
> passing") to reach the same DSL syntax.
>
Well, this IS the real example. The method implementations should not matter
to you to rework the syntax, just adhere to the introduced dependencies. You
might come up with a whole different way of modeling the domain, but that's
not the point.
Steven
Fri, 2009-03-27, 16:47
#26
Re: Draft SIP: Curly import for more authentic DSLs
On Fri, Mar 27, 2009 at 8:27 AM, Steven Obua <obua@me.com> wrote:
> I understand that. I'm just not sure that it's an only way to
> implement DSL like this. That's why I'm asking for the real example. I
> want to try to implement it another way (different than "context
> passing") to reach the same DSL syntax.
>
Well, this IS the real example. The method implementations should not matter
to you to rework the syntax, just adhere to the introduced dependencies. You
might come up with a whole different way of modeling the domain, but that's
not the point.
Steven,
It actually is the point. If there are existing mechanisms within Scala to write a DSL that has a slightly different approach than you want to take, it is worth exploring those. Taking the position that your proposal for implementing DSLs in Scala is the only valid approach does not help move things forward.
From my perspective, I still remain unconvinced that your proposal has any merit at all. What would help convince me and perhaps other members of the community is to try a different approach to the problem. Perhaps a combinator of some sort might address things in a different way. Whether that different is good different or bad different, we won't know until we try. I appreciate Vladimir's willingness to spend the time learning about your domain space in order to answer questions that some of us have.
So, please cooperate with him. I know I'll learn something about your proposal and I suspect others will as well.
Thanks,
David
Steven
--
Best Regards,
Vladimir Kirichenko
--
View this message in context: http://www.nabble.com/Draft-SIP%3A-Curly-import-for-more-authentic-DSLs-tp22719018p22743993.html
Sent from the Scala - Debate mailing list archive at Nabble.com.
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
Fri, 2009-03-27, 17:07
#27
Re: Draft SIP: Curly import for more authentic DSLs
On Fri, Mar 27, 2009 at 4:27 PM, Steven Obua wrote:
>> I understand that. I'm just not sure that it's an only way to
>> implement DSL like this. That's why I'm asking for the real example. I
>> want to try to implement it another way (different than "context
>> passing") to reach the same DSL syntax.
>>
>
> Well, this IS the real example. The method implementations should not matter
> to you to rework the syntax, just adhere to the introduced dependencies. You
> might come up with a whole different way of modeling the domain, but that's
> not the point.
Why not put the methods into an object and make them directly return a
continuation (i.e. Context => Theorem):
object Terms {
def fix(name : String) (cont : Context => Theorem) : Context =>
Theorem = u => {...}
def assume(proposition : String) (cont : Context => Theorem) :
Context => Theorem = u => {...}
// etc.
}
fix ("A")(
fix ("B")(
fix ("C")(
assume ("(A ∨ B) ∨ C")(
// etc.
)))(u)
That would probably complicate the implementation of the methods but
even that's not sure without looking at a concrete implementation.
Johannes
-----------------------------------------------
Johannes Rudolph
http://virtual-void.net
Fri, 2009-03-27, 17:47
#28
Re: Draft SIP: Curly import for more authentic DSLs
On Fri, Mar 27, 2009 at 4:56 PM, Johannes Rudolph
wrote:
> On Fri, Mar 27, 2009 at 4:27 PM, Steven Obua wrote:
>>> I understand that. I'm just not sure that it's an only way to
>>> implement DSL like this. That's why I'm asking for the real example. I
>>> want to try to implement it another way (different than "context
>>> passing") to reach the same DSL syntax.
>>>
>>
>> Well, this IS the real example. The method implementations should not matter
>> to you to rework the syntax, just adhere to the introduced dependencies. You
>> might come up with a whole different way of modeling the domain, but that's
>> not the point.
>
> Why not put the methods into an object and make them directly return a
> continuation (i.e. Context => Theorem):
>
> object Terms {
> def fix(name : String) (cont : Context => Theorem) : Context =>
> Theorem = u => {...}
> def assume(proposition : String) (cont : Context => Theorem) :
> Context => Theorem = u => {...}
> // etc.
> }
>
> fix ("A")(
> fix ("B")(
> fix ("C")(
> assume ("(A ∨ B) ∨ C")(
> // etc.
> )))(u)
>
> That would probably complicate the implementation of the methods but
> even that's not sure without looking at a concrete implementation.
>
I think that this approach may be doable with combinators (to allow
fixing and assuming against the same context etc) for this set of
problem*.
The other alternative I can think of is to use for notation for
structuring of monadic composition, but that can get equally ugly
after the tenth function to be included in the scoped operation.
* using + for andThen
fix("C"){
assume("b v c") + fix("D") +
cases("G") + ...
}
is still readable imo, but I'd prefer:
fix("C"){:
assume("b v c")
fix("D")
cases("G") ...
}
This proposal also allows an easier to program and to read solution to
the threading of implicits (hopefully soon in the sip) as per
http://www.codecommit.com/blog/scala/software-transactional-memory-in-scala.
Whilst my use case is not STM I currently don't like the use of
DynamicVariables to handle the scoping.
The big thing for me is that the use of cps approach makes it more
difficult to embedd normal scala code within the dsl (I'm certain it
can be worked around but that gets yet more complicated).
Fri, 2009-03-27, 18:37
#29
Re: Draft SIP: Curly import for more authentic DSLs
Johannes Rudolph-2 wrote:
>
> Why not put the methods into an object and make them directly return a
> continuation (i.e. Context => Theorem):
>
I definitely like this idea. Basically, what it is doing is changing the
signature of a function from
A => B => C
to
B => A => C,
which should'nt be harmful at all.
I will code my application along these lines (until curly import is
available ;-)) and see if it works out.
Nevertheless, I will continue the SIP process with curly import; for
example, Chris STM example seems to me a good hint that it could prove very
useful. If people know of other good examples, please send them to me, or
post them here, I will submit the SIP only after I got at least 10 promising
applications.
Maybe seeing curly import only in the light of DSLs is a little bit
confusing; I think what curly import might really give you is a powerful way
of writing your own control structures.
Cheers,
Steven
Sun, 2009-03-29, 14:47
#30
Re: Draft SIP: Curly import for more authentic DSLs
I updated the preSip with the STM example.
Vladimir Kirichenko-2 wrote:
>
> Could you please provide some example I could play with?
>
Sun, 2009-03-29, 15:17
#31
Re: Draft SIP: Curly import for more authentic DSLs
I don't understand how the STM example would work unless {: } is re-wrttien as { implicit x => import x._ } Note: The SIP is currently missing the implicit.
I haven't been making very many DSLs, but I tend to come at them from a different angle, usually involving the implicit parameter solution and some kind of interface (see here), so the implicit tweak would be important for the usual style of DSL I tend to create. I'm currently working on a discrete event simulation DSL, however I still haven't run into the issues this SIP is trying to solve. Granted, this SIP would give greater flexibility in defining/creating DSLs, however I think it's possible today to architect decent looking DSLs.
-Josh
On Sun, Mar 29, 2009 at 9:36 AM, Steven Obua <obua@me.com> wrote:
I haven't been making very many DSLs, but I tend to come at them from a different angle, usually involving the implicit parameter solution and some kind of interface (see here), so the implicit tweak would be important for the usual style of DSL I tend to create. I'm currently working on a discrete event simulation DSL, however I still haven't run into the issues this SIP is trying to solve. Granted, this SIP would give greater flexibility in defining/creating DSLs, however I think it's possible today to architect decent looking DSLs.
-Josh
On Sun, Mar 29, 2009 at 9:36 AM, Steven Obua <obua@me.com> wrote:
I updated the preSip with the STM example.
Vladimir Kirichenko-2 wrote:
>
> Could you please provide some example I could play with?
>
--
View this message in context: http://www.nabble.com/Draft-SIP%3A-Curly-import-for-more-authentic-DSLs-tp22719018p22767695.html
Sent from the Scala - Debate mailing list archive at Nabble.com.
Sun, 2009-03-29, 16:37
#32
Re: Draft SIP: Curly import for more authentic DSLs
On Sun, Mar 29, 2009 at 3:06 PM, Josh Suereth wrote:
> I don't understand how the STM example would work unless {: } is re-wrttien
> as { implicit x => import x._ } Note: The SIP is currently missing the
> implicit.
The x is just a container that includes an implictit x. By importing
x._ it imports x's implicits. This is the same as importing implicit
defs or vals by importing ._ on a containing object.
> I haven't been making very many DSLs, but I tend to come at them from a
> different angle, usually involving the implicit parameter solution and some
> kind of interface (see here), so the implicit tweak would be important for
> the usual style of DSL I tend to create. I'm currently working on a
> discrete event simulation DSL, however I still haven't run into the issues
> this SIP is trying to solve. Granted, this SIP would give greater
> flexibility in defining/creating DSLs, however I think it's possible today
> to architect decent looking DSLs.
From my use cases (the stm example pretty much covers the approach) I
want the implicit threaded by the control structure itself. Currently
i achieve this by using dynamic scope, but I would deeply appreciate a
way for the compiler to enforce that certain functions can only be
used within a given set of control structures.
Sun, 2009-03-29, 17:47
#33
Re: Draft SIP: Curly import for more authentic DSLs
I guess, what I'm saying is that I define my DSL on an Object that takes def foo(...arg list...)(implicit val context : MyContext). The only way to call a function is to have the context. Then you define your methods like so...
doSomethingDSLish { ctx => implicit val _ctx = ctx
foo(...)
}
So, in my opinion, I'd rather see syntax like
{ implict ctx => }
or...
{ (implicit arg1, arg2) => }
or even...
{ (arg1 : Type1, implicit arg2 : Type2) => }
before I see {: }.
(Note: I can already write def x(implicit arg1 : Type1), so { implicit arg1 : Type1 => } is not a stretch. Adding in Scala's "drop information that can be inferred" paradigm, { implicit ctx => } is also not a stretch.)
The primary reason here is that your proposal for {: } relies on the compiler being able to infer the types of the arguments and does not generalize to defining functions as values... e.g.
val x = {: } // Compilation Erro!
val x : Function[Type1, Unit] = {: } //This would be ok
It may be possible to generalize my proposal for your case, where maybe something like would compile, and do the correct thing. I think this feature would fall more closely in line with scala's current design, and allow more flexibility.
Finally, I think the idea the "by name" parameters aren't useful and are solved by your SIP is incorrect. To shed more light on your assert example, let's look at "While implemented in scala"
def while(cond : => Boolean)(loop : => Unit) = {
if(cond) {
loop
while(cond)(loop)
}
}
var x = 1;
while(x < 5) {
x = x + 1;
}
If "by name" functions are eliminated....
var x = 1;
while {: x < 5 } {
x = x + 1
}
Automatic Resource management + Retry....
def armWithRetry[A <: Closeable, B](generator : => A)(f : A => B) : B = {
try {
val resource = generator
try {
f(resource)
} finally {
resource.close();
}
} catch {
case IsRetryableOpenResourceException(x) => //Handy extractor
armWithRetry(generator)(f) //This will reallocate the resource and retry from scratch
}
}
normally:
armWithRetry(new FileInputStream("out.txt") {
stream => stream.println("Hello, World!")
}
With your proposal:
armWithRetry {: new FileInputStream("out.txt") } {:
println("Hello, World!")
}
I think we'd be losing a good deal in the DSL world if we took out "by-name parameters" (i.e. no arg functions). In genral I agree with the idea that we can do something to make DSLs even slicker in Scala, however I think {: } may need some reworking (and I'm proposing the implicit alternative)
That said, I'd like to encourage you to continue thinking through the problem! I'm hoping we can eventually come to a means of creating DSLs that feels more "scala" and works well!
-Josh
On Sun, Mar 29, 2009 at 11:34 AM, Chris Twiner <chris.twiner@gmail.com> wrote:
doSomethingDSLish { ctx => implicit val _ctx = ctx
foo(...)
}
So, in my opinion, I'd rather see syntax like
{ implict ctx => }
or...
{ (implicit arg1, arg2) => }
or even...
{ (arg1 : Type1, implicit arg2 : Type2) => }
before I see {: }.
(Note: I can already write def x(implicit arg1 : Type1), so { implicit arg1 : Type1 => } is not a stretch. Adding in Scala's "drop information that can be inferred" paradigm, { implicit ctx => } is also not a stretch.)
The primary reason here is that your proposal for {: } relies on the compiler being able to infer the types of the arguments and does not generalize to defining functions as values... e.g.
val x = {: } // Compilation Erro!
val x : Function[Type1, Unit] = {: } //This would be ok
It may be possible to generalize my proposal for your case, where maybe something like would compile, and do the correct thing. I think this feature would fall more closely in line with scala's current design, and allow more flexibility.
Finally, I think the idea the "by name" parameters aren't useful and are solved by your SIP is incorrect. To shed more light on your assert example, let's look at "While implemented in scala"
def while(cond : => Boolean)(loop : => Unit) = {
if(cond) {
loop
while(cond)(loop)
}
}
var x = 1;
while(x < 5) {
x = x + 1;
}
If "by name" functions are eliminated....
var x = 1;
while {: x < 5 } {
x = x + 1
}
Automatic Resource management + Retry....
def armWithRetry[A <: Closeable, B](generator : => A)(f : A => B) : B = {
try {
val resource = generator
try {
f(resource)
} finally {
resource.close();
}
} catch {
case IsRetryableOpenResourceException(x) => //Handy extractor
armWithRetry(generator)(f) //This will reallocate the resource and retry from scratch
}
}
normally:
armWithRetry(new FileInputStream("out.txt") {
stream => stream.println("Hello, World!")
}
With your proposal:
armWithRetry {: new FileInputStream("out.txt") } {:
println("Hello, World!")
}
I think we'd be losing a good deal in the DSL world if we took out "by-name parameters" (i.e. no arg functions). In genral I agree with the idea that we can do something to make DSLs even slicker in Scala, however I think {: } may need some reworking (and I'm proposing the implicit alternative)
That said, I'd like to encourage you to continue thinking through the problem! I'm hoping we can eventually come to a means of creating DSLs that feels more "scala" and works well!
-Josh
On Sun, Mar 29, 2009 at 11:34 AM, Chris Twiner <chris.twiner@gmail.com> wrote:
On Sun, Mar 29, 2009 at 3:06 PM, Josh Suereth <joshua.suereth@gmail.com> wrote:
> I don't understand how the STM example would work unless {: } is re-wrttien
> as { implicit x => import x._ } Note: The SIP is currently missing the
> implicit.
The x is just a container that includes an implictit x. By importing
x._ it imports x's implicits. This is the same as importing implicit
defs or vals by importing ._ on a containing object.
> I haven't been making very many DSLs, but I tend to come at them from a
> different angle, usually involving the implicit parameter solution and some
> kind of interface (see here), so the implicit tweak would be important for
> the usual style of DSL I tend to create. I'm currently working on a
> discrete event simulation DSL, however I still haven't run into the issues
> this SIP is trying to solve. Granted, this SIP would give greater
> flexibility in defining/creating DSLs, however I think it's possible today
> to architect decent looking DSLs.
From my use cases (the stm example pretty much covers the approach) I
want the implicit threaded by the control structure itself. Currently
i achieve this by using dynamic scope, but I would deeply appreciate a
way for the compiler to enforce that certain functions can only be
used within a given set of control structures.
Sun, 2009-03-29, 18:17
#34
Re: Draft SIP: Curly import for more authentic DSLs
On Sun, Mar 29, 2009 at 5:45 PM, Josh Suereth wrote:
> So, in my opinion, I'd rather see syntax like
> { implict ctx => }
>
> or...
>
> { (implicit arg1, arg2) => }
>
> or even...
>
> { (arg1 : Type1, implicit arg2 : Type2) => }
>
> before I see {: }.
I realise that opinion is what drives this anyway and personally I'd
be okish with implicit x => (it would already remove significant cruft
from my usage) I'd really appreciate the ability to remove that as
well.
> The primary reason here is that your proposal for {: } relies on the
> compiler being able to infer the types of the arguments and does not
> generalize to defining functions as values... e.g.
>
> val x = {: } // Compilation Erro!
>
> val x : Function[Type1, Unit] = {: } //This would be ok
I don't see the problem in this. You can't write
val x = { y => }
either.
> It may be possible to generalize my proposal for your case, where maybe
> something like would compile, and do the correct thing. I think this
> feature would fall more closely in line with scala's current design, and
> allow more flexibility.
> Finally, I think the idea the "by name" parameters aren't useful and are
> solved by your SIP is incorrect. To shed more light on your assert example,
> let's look at "While implemented in scala"
I'd like to add that its not my position that they are "solved" or
that they should be removed at all however ...
> normally:
> armWithRetry(new FileInputStream("out.txt") {
> stream => stream.println("Hello, World!")
> }
>
> With your proposal:
>
> armWithRetry {: new FileInputStream("out.txt") } {:
> println("Hello, World!")
> }
IF they were removed then it would be a simple thing to match that
Unit => Closable instead of the by-name => Closable. I.e. if its Unit
=> T then
{
expresssion Result
}
would be the same.
> I think we'd be losing a good deal in the DSL world if we took out "by-name
> parameters" (i.e. no arg functions).
Again if they were to be removed then Unit => T would be equivalent.
>In genral I agree with the idea that
> we can do something to make DSLs even slicker in Scala, however I think {: }
> may need some reworking (and I'm proposing the implicit alternative)
Note that the implicit alternative only resolves my use case
(threading implicits) not Stevens original justification of importing
the context (._ from the stable identifier parameter). Its something
I could definitely live with and would remove enough cruft to be worth
it (I also think it fits better with the overal usage of scala).
Sun, 2009-03-29, 19:07
#35
Re: Draft SIP: Curly import for more authentic DSLs
Josh Suereth wrote:
>
> I don't understand how the STM example would work unless {: } is
> re-wrttien
> as { implicit x => import x._ } Note: The SIP is currently missing the
> implicit.
>
Josh, this time I tried out the syntax in Scala before putting it into the
presip :-), and yes, it works.
Scala seems to be so smart to even import the implicit attributes of context
members.
Again, I think I have to rephrase my wording about by-name parameters in the
presip. I think they are great; I just like the fact that their lazy
evaluation semantics is a special case of curly import. Actually, if curly
import would have the same native support as by-name parameters, then there
would be no need to write {: }. You could write () instead. Probably curly
import would need a different name then, though.
Honestly, I am not am big fan of the implicit => proposal, because I cannot
see how that helps to make DSLs or control structures more readable or
easier to understand; especially when you nest the stuff this becomes ugly.
Of course, as always, this is just a matter of taste. But then again, {: }
is all about taste, because what {: } does can already be done in Scala
anyway.
Steven
Mon, 2009-03-30, 01:47
#36
Re: Draft SIP: Curly import for more authentic DSLs
On Sun, Mar 29, 2009 at 2:00 PM, Steven Obua <obua@me.com> wrote:
Josh, this time I tried out the syntax in Scala before putting it into the
presip :-), and yes, it works.
Scala seems to be so smart to even import the implicit attributes of context
members.
Again, I think I have to rephrase my wording about by-name parameters in the
presip. I think they are great; I just like the fact that their lazy
evaluation semantics is a special case of curly import. Actually, if curly
import would have the same native support as by-name parameters, then there
would be no need to write {: }. You could write () instead. Probably curly
import would need a different name then, though.
By Name parameters actually work with eta expansion (see page 95 of the Scala language specification). I don't see how {: } would replace this feature. You're not actually writing a no argument function via (), you're making a method call, and the compiler is promoting the expression to a no-argument (or by-name) function. How would {: } be the "general" case of this?
For the one-argument case, these function values are all equivalent:
def someMethod(x : Int) = x + 5
val someLambda = someMethod _
val someLambda1 = (x : Int) => x + 5
val someLambda2 = (_ : Int) + 5
val someLambda3 = { (x : Int) => x + 5 }
val someLambda4 = { x : Int => x + 5 }
val someLambda5 = { ( _ : Int) + 5}
assert(someMethod(1) == someLambda(1))
assert(someLambda(1) == someLambda1(1))
assert(someLambda1(1) == someLambda2(1))
assert(someLambda2(1) == someLambda3(1))
assert(someLambda3(1) == someLambda4(1))
assert(someLambda4(1) == someLambda5(1))
In the context of parameters, you can "degrade" the syntax using some inference...
def doSomething( x : Int => Int) = x(1)
doSomething(x => x + 5)
doSomething(_ + 5)
doSomething { x => x + 5 }
doSomething { _ + 5 }
Your proposal only applies to block (not parenthetical [if that's a term]) expressions. It also only applies to one argument
However, I'd rather not be limited to only using block expressions. Is there any chance we could use some alternate syntax that would work other places? If tuples + arguments become unified for functions, it would be neat to define anonymous closures with numbered placeholders
def dslCommand( f : ((A, B)) => C) = ...
dslCommand {: ( _1 + _2) / _1 } //Would love to do this as a "parenthetical" lambda
Don't get me wrong. I love the idea of the proposal, but it really feels like a "hack around scala syntax" rather than the usual "gracefully allow less information" approach that scala takes (e.g. type inference, semi-colon inference). So, if we can make it slightly more general, or fit in with scala's lambdas/closures/functors, I'd be all for it!
Honestly, I am not am big fan of the implicit => proposal, because I cannot
see how that helps to make DSLs or control structures more readable or
easier to understand; especially when you nest the stuff this becomes ugly.
Of course, as always, this is just a matter of taste. But then again, {: }
is all about taste, because what {: } does can already be done in Scala
anyway.
I agree that it can become somewhat ugly, but it would give you some power and unify things that already exist in scala. I also agree that it's a matter of taste. While I don't like {: specifically, I do like the idea of the proposal and what it could mean. My emails aren't meant to be harsh, only to challenge you to try to come up with a language feature that is more "general".
-Josh
Mon, 2009-03-30, 11:27
#37
Re: Draft SIP: Curly import for more authentic DSLs
> I updated the preSip with the STM example.
Still not really get the point of example. As far as I understand the
main point of SIP is to introduce construct that will make DSL
creation easier. Obviously STM example is not DSL and works only with
hack-like construct like implicit val x = this.
I think that should be clarified the main purpose of the SIP - it says
about DSLs support extensions but shows nonDSL usage examples (assert,
STM). Assert could be implemented with simple by-name parameter with
the same effect, and expression in curly braces got nothing from
"imported context". Another one isn't DSL too and there is nothing bad
with manual import, or passing implicit explicitly, and if there is
another implicit in the scope the usage in specified example causes
conflict between manually declared implicit and "hidden curly
imported" implicit which is really confusing.
So if we're talking about DSLs here it is one thing and here should be
the focus. But introducing of yet another way to declare "lambda"
just to skip parameter declaration in rare cases (STM example) is not
good reason to change language.
Just don't want Scala to become "C++-like-bloated perl with lambdas".
Mon, 2009-03-30, 12:17
#38
Re: Draft SIP: Curly import for more authentic DSLs
On Mon, Mar 30, 2009 at 11:24 AM, Vladimir Kirichenko
wrote:
>> I updated the preSip with the STM example.
>
> Still not really get the point of example. As far as I understand the
> main point of SIP is to introduce construct that will make DSL
> creation easier. Obviously STM example is not DSL and works only with
> hack-like construct like implicit val x = this.
I'm probably responsible for the confusion. I don't have much need
for x => import x._ directly, I'm more interested in removing:
_x =>
implicit val x = _x
which I think you have misunderstood as being hack like.
Unfortunately this is actually the only way to do this declaratively
(verifiable via the compiler) in Scala, i.e. to thread the implicits,
again these may be different at each scope within a given set of
calls. As it stands to remove that cruft (and to allow normal Scala
block usage) I must use either a dynamic scope or monadic composition,
which gets very difficult to read after 10 lines or so of for. I
chose dynamic scope as its far easier to comprehend the code the trade
off being that what could be a compiler error is now a runtime one.
I agree that the STM example is not itself DSL like, what it is
however is an example which could benefit from such a syntatic sugar.
This particular case of threading an individual context could be
implemented as Josh suggests, however this again is a further
extension of Scala syntax, and is IMO less general than the {:
approach (which can be used for anything that benefits from
importing).
> and there is nothing bad
> with manual import, or passing implicit explicitly, and if there is
> another implicit in the scope the usage in specified example causes
> conflict between manually declared implicit and "hidden curly
> imported" implicit which is really confusing.
Again I think things have gotten confused, the idea is not to
magically resolve impliicts or imports but just a splash of syntactic
sugar like (a,b,c) being a Tuple3 or () => X being Function0 etc.
Nothing would change in terms of actual scoping, but it seems to me
that:
x =>
block
expr
also can confuse without the type being specified, indeed the complier
will complain if it finds it confusing. Regarding hiding of implicits
this is already possible, and can already lead to confusion, with
Twitter for example banning their usage.
> So if we're talking about DSLs here it is one thing and here should be
> the focus. But introducing of yet another way to declare "lambda"
> just to skip parameter declaration in rare cases (STM example) is not
> good reason to change language.
Again this seems to be a confusion from the re-use of the general
concept. I personally find it interesting that I can leverage the
concept for threading of implicits with only a minimal change.
By-name is conceptually just sugar for adding () => to the beginning
of a block, but it also doesn't seem to cause too many complaints, it
just seems accepted.
> Just don't want Scala to become "C++-like-bloated perl with lambdas".
I'm curious do you also dislike the 2.8.0 features: virtual classes
support, named parameters ? They are certainaly only aimed at
reducing boilerplate, but require much more change in both the grammar
and the compiler implementation.
The only thing I don't like about the proposal is that {: is pretty
ugly and looks like a typing accident but I honestly don't have a
better suggestion. Josh's
implicit x =>
proposal certainly solves my issue with cruft and readability (and
seems to fit within the overall language design), but I understand it
doesn't apply to Steven's idea.
Mon, 2009-03-30, 12:57
#39
Re: Draft SIP: Curly import for more authentic DSLs
> _x =>
> implicit val x = _x
I though for you example this one is better suitable too.
may be
atomic[T](f: (implicit Transaction => T) :T = f(t) automatically
expanded to your variant is better than implicit val x = this.
Probably
atomic( tx => transfer(...)(tx) ) should not be expanded.
atomic( transfer(...) ) should be expanded to atomic( x => { implicit
val _x = x; transfer(...) )
and it's a subject of separate sip. Also in this variant there is no
restriction to the count of implicit arguments, conflict resolution is
possible, there is no need of new language elements.
> I'm curious do you also dislike the 2.8.0 features: virtual classes
> support, named parameters ?
> They are certainaly only aimed at
> reducing boilerplate, but require much more change in both the grammar
> and the compiler implementation.
Nope:) That's Ok. I'm not against changes, just against badly
motivated changes. We're talking about DSLs, but examples are not
DSLs. Assert could be rewritten using by-name. STM could be
generalized different way as shown at the beginning.
Also {: syntax forces how DSL will look like, and I agree with you
it's pretty ugly.
> Josh's
>
> implicit x =>
>
> proposal certainly solves my issue with cruft and readability (and
> seems to fit within the overall language design), but I understand it
> doesn't apply to Steven's idea.
Agree.
Mon, 2009-03-30, 13:17
#40
Re: Draft SIP: Curly import for more authentic DSLs
On Mon, Mar 30, 2009 at 12:48 PM, Vladimir Kirichenko
wrote:
>> _x =>
>> implicit val x = _x
>
> I though for you example this one is better suitable too.
>
> may be
> atomic[T](f: (implicit Transaction => T) :T = f(t) automatically
> expanded to your variant is better than implicit val x = this.
Sorry I seem to have been at fault here, I just read the presip, I had
thought that the = this was a mistake on your part, but its in the
presip - my appologies. From my perspective:
trait TransactionContext {
implicit val currentTransaction : Transaction
...
}
was intended, not a class and "this".
Indeed, my discussions on the other thread preferred that the implicit
would be defined at the declaration site (as per your above example)
not the use site itself.
> Probably
>
> atomic( tx => transfer(...)(tx) ) should not be expanded.
> atomic( transfer(...) ) should be expanded to atomic( x => { implicit
> val _x = x; transfer(...) )
Thats exactly the use case I have, albeit with with a DI system and
osgi thrown into the mix.
> and it's a subject of separate sip.
If such a presip was accepted then there would be no need for a
seperate sip. However I'm definitely open to that.
> Also in this variant there is no
> restriction to the count of implicit arguments, conflict resolution is
> possible, there is no need of new language elements.
Whilst there are no new language elements the bnf must change as must
the compiler. I don't however see how the conflict resolution is more
possible with this syntax as apposed to the {:, both only require that
you be explicit if there is a colision.
Regarding the count of implicit arguments I'm not sure as to the use
case itself, but I understand the motiviation for uniformity.
>> I'm curious do you also dislike the 2.8.0 features: virtual classes
>> support, named parameters ?
>> They are certainaly only aimed at
>> reducing boilerplate, but require much more change in both the grammar
>> and the compiler implementation.
>
> Nope:) That's Ok. I'm not against changes, just against badly
> motivated changes. We're talking about DSLs, but examples are not
> DSLs. Assert could be rewritten using by-name. STM could be
> generalized different way as shown at the beginning.
I don't disagree with the other points, but what do you understand by
general, the implicit at declaration or implicit x => solutions only
solve one set of issues. I see them as being less general because of
that. However as mentioned they fit better with the overal language
approach imo.
> Also {: syntax forces how DSL will look like, and I agree with you
> it's pretty ugly.
>
{-: is at least funny.
Mon, 2009-03-30, 13:27
#41
Re: Draft SIP: Curly import for more authentic DSLs
As I stated already before, the title "curly import for more authentic DSLs"
is maybe too restricted. It could also be "Curly import for more authentic
DSLs and control structures". Note that the title of the presip is just
curly import. Note that all examples are either DSLs or control structures.
As Chris already said, it is just a simple syntactic extension. I think the
"{: }" syntax is really not the prettiest of syntaxes I have seen in my
life. But it is OK. And it is not something alien put on top of Scala. It is
already in Scala. Curly import just gives this usage pattern a name.
Note that the STM example is not a hack. All the "implicit val
currentTransactionContext" line does is to introduce a name which can be
used to access the current context from within the block. I already
mentioned this usage pattern in the presip before the STM example was clear
to me when I said that "def me = this" could be introduced to access the
current context. Now, because there are implicits in Scala, you can go even
a step further and use the current context implicitly. I cannot see how this
is a hack. In my eyes it is the fruit you reap when your language design is
good.
Steven
I don't get the assert example. Neither its usefulness nor how it
applies to your specification.
Following your specification
myAssert {: 5 > 3 }
should be expanded into
myAssert { context => import context._
5 > 3
}
The parameter would be of type _ => Boolean but myAssert expects () =>
Boolean. So how should that work and what would be the improvement
over the version without Curly import?
How does the feature play along with type-checking? Do you need to
specify the type of the imported parameter and how would that be done?
Johannes
-----------------------------------------------
Johannes Rudolph
http://virtual-void.net
On Thu, Mar 26, 2009 at 11:06 AM, Steven Obua wrote:
>
> Following up a discussion in the "Scala" forum, I would like to submit the
> following draft preSIP:
>
> http://web.me.com/obua/sip_curly_import/sip.xhtml
>
> Best,
>
> Steven Obua
> --
> View this message in context: http://www.nabble.com/Draft-SIP%3A-Curly-import-for-more-authentic-DSLs-...
> Sent from the Scala - Debate mailing list archive at Nabble.com.
>
>