- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Style question: declarative vs procedural
Tue, 2011-12-13, 10:54
I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:
An alternative is to declare these things using methods:
The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
class Foo extends Feature { val name = "Foo" def require = List(Bar, Qux) override def before = List(Qux) override def after = List(Bar)}
An alternative is to declare these things using methods:
class Foo extends Feature { val name = "Foo" require(Bar, Qux) before Qux after Bar}
The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
Tue, 2011-12-13, 12:31
#2
Re: Style question: declarative vs procedural
if you want to keep the syntax and the immutability:
class Foo extends Feature {//feature has an abstract val called meta
val meta = Meta(
name = "i am sonic",
requires = List(a,b),
before = a,
after = b)
}
class Meta(name, require, before, after) {
}
-------- Original-Nachricht --------
> Datum: Tue, 13 Dec 2011 01:54:32 -0800 (PST)
> Von: Marcus Downing
> An: scala-user@googlegroups.com
> Betreff: [scala-user] Style question: declarative vs procedural
> I'm designing a library and need
> to
> provide a way for implementing classes to state certain facts about
> themselves. At the moment this looks like:
>
> class Foo extends Feature {
> val name = "Foo"
> def require = List(Bar, Qux)
> override def before = List(Qux)
> override def after = List(Bar)
> }
>
>
> An alternative is to declare these things using methods:
>
> class Foo extends Feature {
> val name = "Foo"
> require(Bar, Qux)
> before Qux
> after Bar
> }
>
>
> The second certainly reads more easily, but it has a downside: the class
> has now become mutable, something I'm doing my best to avoid. So is the
> syntactic niceness of the second worth the tradeoff of making the code
> procedural rather than declarative?
Tue, 2011-12-13, 16:21
#3
Re: Style question: declarative vs procedural
On Tue, Dec 13, 2011 at 3:54 AM, Marcus Downing <marcus.downing@gmail.com> wrote:
It may appear to be syntactic niceness, but is it really? The former is immutable and will provide you with nice compiler errors if you forget them. The latter not so much. You could also pass them in the constructor, but that's even uglier syntactically, and unnecessary because the values are not needed for construction of Feature, only usage.
I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:class Foo extends Feature { val name = "Foo" def require = List(Bar, Qux) override def before = List(Qux) override def after = List(Bar) }
An alternative is to declare these things using methods:class Foo extends Feature { val name = "Foo" require(Bar, Qux) before Qux after Bar}
The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
It may appear to be syntactic niceness, but is it really? The former is immutable and will provide you with nice compiler errors if you forget them. The latter not so much. You could also pass them in the constructor, but that's even uglier syntactically, and unnecessary because the values are not needed for construction of Feature, only usage.
Wed, 2011-12-14, 15:31
#4
Re: Style question: declarative vs procedural
No.
I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:class Foo extends Feature { val name = "Foo" def require = List(Bar, Qux) override def before = List(Qux) override def after = List(Bar) }
An alternative is to declare these things using methods:class Foo extends Feature { val name = "Foo" require(Bar, Qux) before Qux after Bar}
The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
Wed, 2011-12-14, 15:31
#5
Re: Style question: declarative vs procedural
What about:
abstract class Feature(val name: String, val require: Seq[Feature] = Seq.empty, val before: Seq[Feature] = Seq.empty, val after: Seq[Feature] = Seq.empty) {}
class Foo extends Feature( name = "Foo", require = Seq(Bar, Quz) // No more needed if I don't need different values.) {
// Normal overrides here....}
On Tue, Dec 13, 2011 at 4:54 AM, Marcus Downing <marcus.downing@gmail.com> wrote:
abstract class Feature(val name: String, val require: Seq[Feature] = Seq.empty, val before: Seq[Feature] = Seq.empty, val after: Seq[Feature] = Seq.empty) {}
class Foo extends Feature( name = "Foo", require = Seq(Bar, Quz) // No more needed if I don't need different values.) {
// Normal overrides here....}
On Tue, Dec 13, 2011 at 4:54 AM, Marcus Downing <marcus.downing@gmail.com> wrote:
I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:class Foo extends Feature { val name = "Foo" def require = List(Bar, Qux) override def before = List(Qux) override def after = List(Bar) }
An alternative is to declare these things using methods:class Foo extends Feature { val name = "Foo" require(Bar, Qux) before Qux after Bar}
The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
Wed, 2011-12-14, 15:41
#6
Re: Style question: declarative vs procedural
Hi,
isn't that pretty much exactly like my first answer in this thread? :)
Kind regards
Andreas
Josh Suereth wrote:
> What about:
>
> abstract class Feature(val name: String, val require: Seq[Feature] = Seq.empty, val before: Seq[Feature] = Seq.empty, val after: Seq[Feature] = Seq.empty) {}
>
> class Foo extends Feature(
> name = "Foo",
> require = Seq(Bar, Quz)
> // No more needed if I don't need different values.
> ) {
>
> // Normal overrides here....
> }
>
> On Tue, Dec 13, 2011 at 4:54 AM, Marcus Downing wrote:
> I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:
>
> class Foo extends Feature {
> val name = "Foo"
> def require = List(Bar, Qux)
> override def before = List(Qux)
> override def after = List(Bar)
> }
>
> An alternative is to declare these things using methods:
>
> class Foo extends Feature {
> val name = "Foo"
> require(Bar, Qux)
> before Qux
> after Bar
> }
>
> The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
>
Wed, 2011-12-14, 16:11
#7
Re: Style question: declarative vs procedural
Opps, that's correct. Sorry, I got to this one pretty late :)
Note: <collection>.empty rather than Seq() is a meme I'm trying to push though!
- Josh
On Wed, Dec 14, 2011 at 9:39 AM, Andreas Flierl <andreas@flierl.eu> wrote:
Note: <collection>.empty rather than Seq() is a meme I'm trying to push though!
- Josh
On Wed, Dec 14, 2011 at 9:39 AM, Andreas Flierl <andreas@flierl.eu> wrote:
Hi,
isn't that pretty much exactly like my first answer in this thread? :)
Kind regards
Andreas
Josh Suereth wrote:
> What about:
>
> abstract class Feature(val name: String, val require: Seq[Feature] = Seq.empty, val before: Seq[Feature] = Seq.empty, val after: Seq[Feature] = Seq.empty) {}
>
> class Foo extends Feature(
> name = "Foo",
> require = Seq(Bar, Quz)
> // No more needed if I don't need different values.
> ) {
>
> // Normal overrides here....
> }
>
> On Tue, Dec 13, 2011 at 4:54 AM, Marcus Downing <marcus.downing@gmail.com> wrote:
> I'm designing a library and need to provide a way for implementing classes to state certain facts about themselves. At the moment this looks like:
>
> class Foo extends Feature {
> val name = "Foo"
> def require = List(Bar, Qux)
> override def before = List(Qux)
> override def after = List(Bar)
> }
>
> An alternative is to declare these things using methods:
>
> class Foo extends Feature {
> val name = "Foo"
> require(Bar, Qux)
> before Qux
> after Bar
> }
>
> The second certainly reads more easily, but it has a downside: the class has now become mutable, something I'm doing my best to avoid. So is the syntactic niceness of the second worth the tradeoff of making the code procedural rather than declarative?
>
Fri, 2011-12-16, 04:41
#8
Re: Style question: declarative vs procedural
On Tuesday, December 13, 2011, Marcus Downing <marcus.downing@gmail.com> wrote:
> before Qux
> after Bar
You can't really do that. scalac sees that as "call method Qux of value before." You need parenthesis.
Fri, 2011-12-16, 12:21
#9
Re: Style question: declarative vs procedural
Named, default arguments does look like a nice way of doing it, that has reasonable syntax as well as immutability. Feature is currently a trait, but can be a class for the sake of getting this configuration right.
Why the split parameter list though?
vs
Thanks to Andreas - and Josh - for the answer.
Why the split parameter list though?
class Foo extends Feature( name = "Foo", required = List(...))( before = List(...) )
vs
class Foo extends Feature( name = "Foo", required = List(...), before = List(...) )
Thanks to Andreas - and Josh - for the answer.
Fri, 2011-12-16, 12:51
#10
Re: Style question: declarative vs procedural
Hi,
the default arguments of the second parameter list can use the ones from the
first, e.g. the default value for "before" is whatever was given to "required"
in my example. I just wanted to show you that this is possible, in case you'd
need it.
Kind regards
Andreas
Marcus Downing wrote:
> Named, default arguments does look like a nice way of doing it, that has
> reasonable syntax as well as immutability. Feature is currently a trait, but
> can be a class for the sake of getting this configuration right.
> Why the split parameter list though?
>
>
> > class Foo extends Feature(
> > name = "Foo",
> > required = List(...)
> > )(
> > before = List(...)
> > )
> >
> vs
>
>
> > class Foo extends Feature(
> >
> > name = "Foo",
> >
> > required = List(...),
> >
> > before = List(...)
> >
> > )
> >
> >
Fri, 2011-12-16, 14:41
#11
Re: Style question: declarative vs procedural
Ah, I see - DRY. The trade-off is that it requires the second brackets to be present all the time.
Having implemented this, I can tell just from the change to all my test cases that it's an improvement in readability. Not only is is shorter, more importantly the cases with and without each of the optional arguments look less similar, so it's easier to tell the intent of code with a glance.
Having implemented this, I can tell just from the change to all my test cases that it's an improvement in readability. Not only is is shorter, more importantly the cases with and without each of the optional arguments look less similar, so it's easier to tell the intent of code with a glance.
Hi,
Marcus Downing asked:
> The second certainly reads more easily, but it has a downside: the class has
> now become mutable, something I'm doing my best to avoid. So is the syntactic
> niceness of the second worth the tradeoff of making the code procedural rather
> than declarative?
>
I'd say: no.
Is Feature a trait or a class? If it's a class, why not ask for name, required,
before and after as constructor parameters?
class Feature(val name: String, val required: Seq[Any])(val before: Seq[Any] =
required, val after: Seq[Any] = required)
(I took Any (and some other assumptions) here because I have no idea about the
type constraints of your methods.)
Then you could say:
class Foo extends Feature("Foo", Seq(...))(Seq(...), Seq(...))
or
class Foo extends Feature(
name = "Foo",
required = Seq(...)
)(
before = Seq(...),
after = Seq(...)
)
or leave after as default
class Foo extends Feature(
name = "Foo",
required = Seq(...)
)(
before = Seq(...)
)
I hope that helped a bit.
Kind regards
Andreas