The Artima Developer Community
Sponsored Link

Weblogs Forum
Pimp my Library

32 replies on 3 pages. Most recent reply: Aug 17, 2012 6:35 AM by Ugo Matrangolo

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 32 replies on 3 pages [ 1 2 3 | » ]
Martin Odersky

Posts: 84
Nickname: modersky
Registered: Sep, 2003

Pimp my Library (View in Weblogs)
Posted: Oct 9, 2006 1:17 PM
Reply to this message Reply
Summary
What to do if you are stuck with existing libraries and API's.
Advertisement

There's a fundamental difference between your own code and libraries of other people: You can change or extend your own code, but if you want to use some other libraries you have to take them as they are.

A number of constructs have sprung up in programming languages to alleviate this problem. Smalltalk has meta classes, Ruby has modules. These are very powerful, but also dangerous, in that you modify the behavior of a class for an entire application, some parts of which you might not know. C# 3.0 has method extensions, which are more local, but also more restrictive in that you can only add methods, not fields or interfaces to a class.

Scala has implicit parameters and conversions. They can make existing libraries much more pleasant to deal with. A particularly nice example is a wrapper for simplifying JDBC, written by Ross Judson (I misattributed this to Jamie Webb in the original version of the blog; my apologies).

The rest of this blog explains what implicits are (you can skip it if you know it already, or if you don't care). Say you have a value x of type Array[int] and you want to assign this value to some variable of type String:

var v: String = x

Array[int] does not conform to String, so normally this would give a type error. However, you can define a conversion function from arrays of arbitrary element type T to String, like this:

implicit def array2string[T](x: Array[T]) = x.toString

(Yes, arrays have a usable toString method in Scala!). The only non-standard aspect of this function is its implicit modifier, which labels it as an implicit conversion. If such an implicit conversion is visible at the point of an otherwise illegal assignment, the conversion is automatically inserted. So the above assignment would be expanded to:

var v: String = array2string(x)

Implicit conversions can also be applied in other situations. For instance they can be applied when selecting a member of some value which is undefined in its type. An example is an append operator on arrays, to be used as in the following:

val x = Array(1, 2, 3)
val y = Array(4, 5, 6)
val z = x append y

Scala parses the last expression as a method call: x.append(y). The problem is that Scala's arrays are directly mapped to Java's arrays, and there is no append method in either type! However, implicit conversions can help. We need to define a new class, say RichArray, which defines an append method (and which might also define other methods we want to add to the Array type):

class RichArray[T](value: Array[T]) {
  def append(other: Array[T]): Array[T] = {
    val result = new Array[T](value.length + other.length)
    Array.copy(value, 0, result, 0, value.length)
    Array.copy(other, 0, result, value.length, other.length)
    result
  }
}

Now, all that remains is to define an implicit conversion from plain arrays to rich arrays:

implicit def enrichArray[T](xs: Array[T]) = new RichArray[T]

With this conversion, we have effectively enriched Java's array class with an append method.


Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Pimp my Library Posted: Oct 9, 2006 3:00 PM
Reply to this message Reply
Damn! That's very cool!

Eivind Eklund

Posts: 49
Nickname: eeklund2
Registered: Jan, 2006

Re: Pimp my Library Posted: Oct 10, 2006 7:24 AM
Reply to this message Reply
Doesn't this give trouble in practice? I've found the conversion features of C++ to lead to some of the more insidious bugs I've had to debug.

Jay Sachs

Posts: 30
Nickname: jaysachs
Registered: Jul, 2005

Re: Pimp my Library Posted: Oct 10, 2006 10:07 AM
Reply to this message Reply
I wonder the same thing. If there are two implicit conversion paths, does the Scala compiler complain, or pick one based on scoping or other criteria?

Martin Odersky

Posts: 84
Nickname: modersky
Registered: Sep, 2003

Re: Pimp my Library Posted: Oct 10, 2006 10:37 AM
Reply to this message Reply
> I wonder the same thing. If there are two implicit
> conversion paths, does the Scala compiler complain, or
> pick one based on scoping or other criteria?

That depends. In a sense, implicits are treated as overloaded functions. If there are several applicable implicits, the Scala compiler will apply overloading resulution to pick a most specific one. If there is no unique best conversion, an ambiguity error results.

Example:

implicit def string2int(x: String): int = x.length
implicit def object2int(x: Object): int = x.hashCode

val x: int = "abc"

In that case, the string2int conversion will be picked, because it is more specific than the object2int conversion. On the other hand, if we added another conversion

implicit def string2intAlt(x: String): int = x.hashCode

this would give an ambiguity error.

Jay Sachs

Posts: 30
Nickname: jaysachs
Registered: Jul, 2005

Re: Pimp my Library Posted: Oct 10, 2006 3:04 PM
Reply to this message Reply
So if I do an inopportune "promiscuous import", I may end up importing a more specific set of conversions, and thus the behaviour of my program will change?

Martin Odersky

Posts: 84
Nickname: modersky
Registered: Sep, 2003

Re: Pimp my Library Posted: Oct 10, 2006 4:22 PM
Reply to this message Reply
> So if I do an inopportune "promiscuous import", I may end
> up importing a more specific set of conversions, and thus
> the behaviour of my program will change?

Yes. Implicits are very powerful but you should use them with care.

-- Martin

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

This was a bad idea in C++ Posted: Oct 10, 2006 5:42 PM
Reply to this message Reply
and repeating the mistake in another language doesn't make it better.

In general, I find that automatic type conversion leads to programs that are fragile with performance that is difficult to predict and occasionally very surprising behavior.

If you have something and you want it to become something else, its not a burden to call the conversion. IOW

String x = someObject.toString();

makes it clear that type conversion is occurring to the reader. But

String x = someNonStringObject;

would lead the casual reader to assume that someNonStringObject is of a type compatibile with String.

So you've just eliminated a valuable aspect of communication between coder and reader and made the program just a bit more cryptic.

This is the kind of nonsense that lead me to abandon C++.

Kay Schluehr

Posts: 302
Nickname: schluehk
Registered: Jan, 2005

Re: This was a bad idea in C++ Posted: Oct 11, 2006 3:04 AM
Reply to this message Reply
> If you have something and you want it to become something
> else, its not a burden to call the conversion. IOW
>
> String x = someObject.toString();

You might have overlooked that 'implicit' is a declarative that affects the whole component. So it's about not writing boilerplate in each place when an existing component shall be coupled to another with slightly different conventions. You might even replace the component by an other one by just replacing the 'implicit' conversion without touching the code otherwise. If your UTs fail afterwards you still can handcraft the conversions and trash implicit.

disney

Posts: 35
Nickname: juggler
Registered: Jan, 2003

Re: This was a bad idea in C++ Posted: Oct 11, 2006 5:44 AM
Reply to this message Reply
Todd wrote:
<But String x = someNonStringObject; would lead the casual reader to assume that someNonStringObject is of a type compatibile with String. So you've just eliminated a valuable aspect of communication between coder and reader and made the program just a bit more cryptic. This is the kind of nonsense that lead me to abandon C++.>

I wonder if it is fair to criticise C++ because it allows you to write non-intuitive code? Is there really a better alternative? ;-)

I agree with everything you say, but suspect that writing good code that is easy to understand, maintain and extend may only be achieved by professional discipline.

If anyone knows of a language that can help us in this respect, I would *love* to hear about it...?

Eivind Eklund

Posts: 49
Nickname: eeklund2
Registered: Jan, 2006

Re: This was a bad idea in C++ Posted: Oct 11, 2006 8:25 AM
Reply to this message Reply
Steve wrote:
> Todd wrote:
> I wonder if it is fair to criticise C++ because it allows
> you to write non-intuitive code? Is there really a better
> alternative? ;-)

>
> I agree with everything you say, but suspect that writing
> good code that is easy to understand, maintain and extend
> may only be achieved by professional discipline.
>
> If anyone knows of a language that can help us in this
> respect, I would *love* to hear about it...?

Ruby (in my opinion) does well in this regard (even though it comes with even more aparatus that CAN be used for foot-shooting than C++), as does Eiffel.

Part of this is that the language is designed without significant areas where it's too easy and tempting to write really weird code and have it look like it is normal.

An example of this in C++ is the references syntax: In other languages, what end up as references and what end up as being passed by value is implictly defined. This means that when you look at a call and know what the various parameters are, you also know whether they are passed by reference or value - ie, whether they may or may not be changed after the call. In C++, the & operator override this - and I've relatively often seen people write void f(int & varToChange); instead of void f(int *varToChange); because they see the calling convention f(&lexicalVariable); as ugly, and they want to modify the variable in the caller's scope.

I've also seen really weird stuff come out from the conversion rules in C++, and a lot of abuse of overloading. These are problems that aren't available in many other languages: There simply is no way to get inconsistent behaviour. This means that it's much simpler to be sure of what happens at the point of call in these languages, and that decrease the amount of problems in programs produced in them.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: This was a bad idea in C++ Posted: Oct 11, 2006 9:15 AM
Reply to this message Reply
> I wonder if it is fair to criticise C++ because it allows
> you to write non-intuitive code? Is there really a better
> alternative? ;-)

Don't get me wrong here, I completely see where you are coming from but someone could make the sme argument about assembly or machine code. My personal opinion is that C++ allows things that are not only problematic from a maintenance perspective, it also allow things that are dangerous and, frankly, unnecessary. As I use more languages and learn more about Scala, C++ seems more and more like a dinosaur, COBOLishly archaic, perhaps.

But again I do agree that a language should help us solve problems and not second-guess us at every turn, however, it easy to demonstrate that the argument that anything goes and if there's an issue, it's the developers fault doesn't hold a lot of water. There's a middle ground and I don't think there is one answer.

Imam Alam

Posts: 3
Nickname: uchchwhash
Registered: Jul, 2006

Re: This was a bad idea in C++ Posted: Oct 11, 2006 1:51 PM
Reply to this message Reply
IMHO Java has an implicit conversion:

System.out.println("" + (3.0/4));

works fine and no one really complains about it!

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: This was a bad idea in C++ Posted: Oct 11, 2006 5:07 PM
Reply to this message Reply
> IMHO Java has an implicit conversion:
>
> System.out.println("" + (3.0/4));

Technically that's an overloaded operator and not an implicit conversion.

Also you can just do this:

System.out.println(3.0/4);

Which looks more like an implicit conversion but is just a overloaded method.

This really doesn't compare to what an implicit conversion does. It also doesn't introduce the danger that was described above.

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

Re: This was a bad idea in C++ Posted: Oct 12, 2006 10:27 PM
Reply to this message Reply
>You might have overlooked that 'implicit' is a declarative that affects the whole component.

No, I caught that. But implicit behavior leads to assumptions and assumptions lead to bugs.

FORTRAN had an implicit typing convention that determined the type of a variable based on what letter it started with. In the 77 version, a declaration IMPLICIT NONE was added to turn this feature off and require explicit typing because the old behavior was a source of bugs.

Many bugs in C++ stem from automatic unexpected type conversions.

In general, "magic" features often produce unexpected results, which cause bugs, and so should be avoided in language design.

Flat View: This topic has 32 replies on 3 pages [ 1  2  3 | » ]
Topic: Gentle Introduction to Scala: The Seminar Previous Topic   Next Topic Topic: Software Documentation Is Like Weather and Pornography


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us