Quantcast

Fluent style support

Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Fluent style support

Mick Epstrewce
Calling methods in a fluent style is nice, but declaring and implementing the methods of a fluent API is not elegant in Scala because it is necessary:

  1. to return 'this' as the last expression in the methods body and
  2. to declare the result type of the operation as 'this.type' in the API (instead of the conceptually correct type Unit) - a pollution of the conceptual API with technical details

In Smalltalk there is a special syntax construct for cascaded messages:

receiver message1 ; message 2

allowing to use a fluent style without the necessity to prepare any method for this purpose.
But the Smalltalk syntax used for cascaded messages is hard to parse (by readers) when the receiver is itself the result of a message send, e.g. like

receiver message1 message 2 ; message 3

which is equivalent to

(receiver message1) message 2 ; message 3


My proposal for a syntax exension of Scala to express cascaded messages is:

receiver.{message1; message 2}

The compiler can translate this to something like:

 {import receiver; message1; message2}

The compiler should complain and reject this cascaded message expression when there is another object imported (in the context of this expression) which understands some of the messages, because this would lead to ambiguities - and would again be hard to parse (by readers).
Also the dot between receiver and opening curly brace is required to ensure proper interpretation (by the compiler).

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Vlad Patryshev
I got a feeling that this fluent approach is only good in OOP with mutable data.
Alternatively, loops in Scala allow a lot of similar expressiveness.

Thanks,
-Vlad

On Sat, Jan 21, 2017 at 4:35 PM, Mick Epstrewce <[hidden email]> wrote:
Calling methods in a fluent style is nice, but declaring and implementing the methods of a fluent API is not elegant in Scala because it is necessary:

  1. to return 'this' as the last expression in the methods body and
  2. to declare the result type of the operation as 'this.type' in the API (instead of the conceptually correct type Unit) - a pollution of the conceptual API with technical details

In Smalltalk there is a special syntax construct for cascaded messages:

receiver message1 ; message 2

allowing to use a fluent style without the necessity to prepare any method for this purpose.
But the Smalltalk syntax used for cascaded messages is hard to parse (by readers) when the receiver is itself the result of a message send, e.g. like

receiver message1 message 2 ; message 3

which is equivalent to

(receiver message1) message 2 ; message 3


My proposal for a syntax exension of Scala to express cascaded messages is:

receiver.{message1; message 2}

The compiler can translate this to something like:

 {import receiver; message1; message2}

The compiler should complain and reject this cascaded message expression when there is another object imported (in the context of this expression) which understands some of the messages, because this would lead to ambiguities - and would again be hard to parse (by readers).
Also the dot between receiver and opening curly brace is required to ensure proper interpretation (by the compiler).

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Naftoli Gugenheim
In reply to this post by Mick Epstrewce
You can do something like this:

implicit class FluentExtensionMethod[A](private val self: A) {
  def fluently(actions: (A => Unit)*) = actions.foreach(_(self))
}

person.fluently(
  _.setName("Jack"),
  _.setAge(55),
  _.setCountry("US")
)


On Sat, Jan 21, 2017 at 7:35 PM Mick Epstrewce <[hidden email]> wrote:
Calling methods in a fluent style is nice, but declaring and implementing the methods of a fluent API is not elegant in Scala because it is necessary:

  1. to return 'this' as the last expression in the methods body and
  2. to declare the result type of the operation as 'this.type' in the API (instead of the conceptually correct type Unit) - a pollution of the conceptual API with technical details

In Smalltalk there is a special syntax construct for cascaded messages:

receiver message1 ; message 2

allowing to use a fluent style without the necessity to prepare any method for this purpose.
But the Smalltalk syntax used for cascaded messages is hard to parse (by readers) when the receiver is itself the result of a message send, e.g. like

receiver message1 message 2 ; message 3

which is equivalent to

(receiver message1) message 2 ; message 3


My proposal for a syntax exension of Scala to express cascaded messages is:

receiver.{message1; message 2}

The compiler can translate this to something like:

 {import receiver; message1; message2}

The compiler should complain and reject this cascaded message expression when there is another object imported (in the context of this expression) which understands some of the messages, because this would lead to ambiguities - and would again be hard to parse (by readers).
Also the dot between receiver and opening curly brace is required to ensure proper interpretation (by the compiler).

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Mick Epstrewce
The solution with an implicit method ('fluently') is good enough in my opinion, so no language extension is needed :-)
Maybe here the use of an operator symbol is justified, e.g. I would rename 'fluently'  to '!!'.


Am Sonntag, 22. Januar 2017 10:38:08 UTC+1 schrieb nafg:
You can do something like this:

implicit class FluentExtensionMethod[A](private val self: A) {
  def fluently(actions: (A => Unit)*) = actions.foreach(_(self))
}

person.fluently(
  _.setName("Jack"),
  _.setAge(55),
  _.setCountry("US")
)


On Sat, Jan 21, 2017 at 7:35 PM Mick Epstrewce <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="7yhpXcTqGAAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">mick5...@...> wrote:
Calling methods in a fluent style is nice, but declaring and implementing the methods of a fluent API is not elegant in Scala because it is necessary:

  1. to return 'this' as the last expression in the methods body and
  2. to declare the result type of the operation as 'this.type' in the API (instead of the conceptually correct type Unit) - a pollution of the conceptual API with technical details

In Smalltalk there is a special syntax construct for cascaded messages:

receiver message1 ; message 2

allowing to use a fluent style without the necessity to prepare any method for this purpose.
But the Smalltalk syntax used for cascaded messages is hard to parse (by readers) when the receiver is itself the result of a message send, e.g. like

receiver message1 message 2 ; message 3

which is equivalent to

(receiver message1) message 2 ; message 3


My proposal for a syntax exension of Scala to express cascaded messages is:

receiver.{message1; message 2}

The compiler can translate this to something like:

 {import receiver; message1; message2}

The compiler should complain and reject this cascaded message expression when there is another object imported (in the context of this expression) which understands some of the messages, because this would lead to ambiguities - and would again be hard to parse (by readers).
Also the dot between receiver and opening curly brace is required to ensure proper interpretation (by the compiler).

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="7yhpXcTqGAAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-debate...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Nils Kilden-Pedersen
In reply to this post by Vlad Patryshev
On Sat, Jan 21, 2017 at 7:41 PM, Vlad Patryshev <[hidden email]> wrote:
I got a feeling that this fluent approach is only good in OOP with mutable data.

Why? The signature is mutable/immutable agnostic. For mutable you return this, for immutable you return new.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Vlad Patryshev

On Thu, Feb 2, 2017 at 9:59 AM, Nils Kilden-Pedersen <[hidden email]> wrote:
On Sat, Jan 21, 2017 at 7:41 PM, Vlad Patryshev <[hidden email]> wrote:
I got a feeling that this fluent approach is only good in OOP with mutable data.

Why? The signature is mutable/immutable agnostic. For mutable you return this, for immutable you return new.


Hmm, can you show an example of this?

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Nils Kilden-Pedersen

On Thu, Feb 2, 2017 at 1:07 PM, Vlad Patryshev <[hidden email]> wrote:


On Thu, Feb 2, 2017 at 9:59 AM, Nils Kilden-Pedersen <[hidden email]> wrote:
On Sat, Jan 21, 2017 at 7:41 PM, Vlad Patryshev <[hidden email]> wrote:
I got a feeling that this fluent approach is only good in OOP with mutable data.

Why? The signature is mutable/immutable agnostic. For mutable you return this, for immutable you return new.


Hmm, can you show an example of this?

trait Foo {
  def name: String
  def name(n: String): this.type

  def limit: Int
  def limit(l: Int): this.type
}

class MutableFoo 
    extends Foo {
  private var _name: String = _
  private var _limit: Int = _

  def name: String = _name
  def name(n: String) = {
    _name = n
    this
  }

  def limit: Int = _limit
  def limit(l: Int) = {
    _limit = l
    this
  }
}

case class ImmutableFoo(name: String, limit: Int) 
    extends Foo {

  def name(n: String) = this.copy(name = n).asInstanceOf[this.type]
  def limit(l: Int) = this.copy(limit = l).asInstanceOf[this.type]
}

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Naftoli Gugenheim

There's a reason you need the asInstanceOf, you aren't really conforming to the singleton type


On Thu, Feb 2, 2017, 3:56 PM Nils Kilden-Pedersen <[hidden email]> wrote:

On Thu, Feb 2, 2017 at 1:07 PM, Vlad Patryshev <[hidden email]> wrote:


On Thu, Feb 2, 2017 at 9:59 AM, Nils Kilden-Pedersen <[hidden email]> wrote:
On Sat, Jan 21, 2017 at 7:41 PM, Vlad Patryshev <[hidden email]> wrote:
I got a feeling that this fluent approach is only good in OOP with mutable data.

Why? The signature is mutable/immutable agnostic. For mutable you return this, for immutable you return new.


Hmm, can you show an example of this?

trait Foo {
  def name: String
  def name(n: String): this.type

  def limit: Int
  def limit(l: Int): this.type
}

class MutableFoo 
    extends Foo {
  private var _name: String = _
  private var _limit: Int = _

  def name: String = _name
  def name(n: String) = {
    _name = n
    this
  }

  def limit: Int = _limit
  def limit(l: Int) = {
    _limit = l
    this
  }
}

case class ImmutableFoo(name: String, limit: Int) 
    extends Foo {

  def name(n: String) = this.copy(name = n).asInstanceOf[this.type]
  def limit(l: Int) = this.copy(limit = l).asInstanceOf[this.type]
}

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Nils Kilden-Pedersen
On Thu, Feb 2, 2017 at 3:41 PM, Naftoli Gugenheim <[hidden email]> wrote:

There's a reason you need the asInstanceOf, you aren't really conforming to the singleton type

True, but it was sort of a contrived example anyways. My original point still stands, I believe.

 

On Thu, Feb 2, 2017, 3:56 PM Nils Kilden-Pedersen <[hidden email]> wrote:

On Thu, Feb 2, 2017 at 1:07 PM, Vlad Patryshev <[hidden email]> wrote:


On Thu, Feb 2, 2017 at 9:59 AM, Nils Kilden-Pedersen <[hidden email]> wrote:
On Sat, Jan 21, 2017 at 7:41 PM, Vlad Patryshev <[hidden email]> wrote:
I got a feeling that this fluent approach is only good in OOP with mutable data.

Why? The signature is mutable/immutable agnostic. For mutable you return this, for immutable you return new.


Hmm, can you show an example of this?

trait Foo {
  def name: String
  def name(n: String): this.type

  def limit: Int
  def limit(l: Int): this.type
}

class MutableFoo 
    extends Foo {
  private var _name: String = _
  private var _limit: Int = _

  def name: String = _name
  def name(n: String) = {
    _name = n
    this
  }

  def limit: Int = _limit
  def limit(l: Int) = {
    _limit = l
    this
  }
}

case class ImmutableFoo(name: String, limit: Int) 
    extends Foo {

  def name(n: String) = this.copy(name = n).asInstanceOf[this.type]
  def limit(l: Int) = this.copy(limit = l).asInstanceOf[this.type]
}

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Jasper-M
Well, in your opening post you said the correct type of the methods you have in mind is `Unit`. That sort of implies mutability.

Kind regards,
Jasper

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fluent style support

Jasper-M
I'm sorry, it wasn't you :-p But you get my point.

kr,
Jasper

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Loading...