Not quite getting it

Hi,
I’m trying to get whats Ruby is all about.
I’ve been doing .NET since beta so I’m kind of stuck in the static typed
mindset.

The parts that I do get:

I love metaprogramming, I was able to make a port of my .NET AOP
framework that took about 3 months to do in .NET in a week in Ruby (w/o
ever touching ruby before… )

I also understand that its nice with auto promotion of number types when
they would overflow in other languages.

What I don’t get:

How do you deal with ducktyping?
How can anyone assume that just because a method exists that the
semantics is the same?

Brush.Draw( x , y )
vs
Cowboy.Draw( direction, speed )

The same name and signature, not even close to the same semantic
meaning.

Doesnt this put an extra burden on the developer, that he has to know
the exact intention of each and every method?
Where in a language that supports ifaces you simply know that the
methods associated with the interface have a certain meaning.

The backside of dynamic typing.
I got a mail from a newsgroup a few days ago with the title “we once
overflowed a long at google”

Ok ok, as I said, I get type promotion.
But what if you assign a “Giraffe” to a property called “Orders” , isnt
that just as bad or even worse than overflowing a number?

If someone say “that should be caught in a unit test” , well so should
the overflowed long (And Java and .NET can use big integers etc too if
you need)

And the thing that I have the hardest time with, how the heck do you
learn to use someone elses framework / api ?

in a typed language with decent intellisense I can see what types Im
supposed to pass in and what I get back.
One can often understand how to use an API by just looking at the
intellisense.

While I found myself browsing ruby docs back and forth just to see if
the result of a method would be a string or an object etc.

So can someone try to convert me or am I forever lost? :stuck_out_tongue:

“in a typed language”

Before I get killed, I ment static typed…

On May 16, 2008, at 1:45 PM, Roger A. wrote:

Doesnt this put an extra burden on the developer, that he has to know
the exact intention of each and every method?

I kinda think that this is the basis of programming in any language…

Here’s the thing. I’m sure many people will try to convince you–this
may end up being a thread that runs and runs.

Ignore them. They’ll never change your mind.

The only thing that will is for you to try it. Try Ruby on larger
programs. Try it for a month or too. And see what happens. If your
programs die because brushes end up shooting people, then Ruby isn’t
the language for you. If instead you continue to enjoy a factor of 12
productivity improvement, maybe it is.

Everyone’s mileage will vary.

Dave

On 5/16/08, Roger A. [email protected] wrote:

vs

you need)
the result of a method would be a string or an object etc.

So can someone try to convert me or am I forever lost? :stuck_out_tongue:


Posted via http://www.ruby-forum.com/.

Very oft brought up question, and valid in some points.

int someInterestingMethod(int x, int y, float spock) {

}

What do those parameters mean? What do you pass into this function and
what are you supposed to get out? Just having static types does not at
all help with understanding what a function does. You need well named
functions and arguments, with documentation on what the function
does and what parameters are supposed to be. This is no different in a
statically typed language vs dynamically typed language.

The only thing a static typed language guarantees is that proper types
were passed into the function. That’s no guarantee that you’re using
the function correctly or that the function itself works at all. Only
a comprehensive test suite will catch these kind of problems.

Things like overflowing a float will happen to anyone in any language.

So in short, all code should have:

  1. documentation of what the method does, what the parameters are and
    what the return is.
  2. properly named functions and parameters.

neither of which has anything to do with the typing system of the
language. There will be libraries who’s maintainers don’t document
anything, leaving you to experiment and ask around. This is true for
all programming and is something we just have to live with (and
hopefully not propogate).

Hope that helps you understand why dynamic vs static typing really
isn’t a issue.

Jason

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On May 16, 2008, at 8:45 PM, Roger A. wrote:

How do you deal with ducktyping?
How can anyone assume that just because a method exists that the
semantics is the same?

Brush.Draw( x , y )
vs
Cowboy.Draw( direction, speed )

The same name and signature, not even close to the same semantic
meaning.

Actually, how do you guarantee those semantics in a statically typed
language?

Consider this (pseudo-java, sorry :wink: ):

interface Drawable
{
abstract public void draw(int a, int b);
}

class Point implements Drawable
{
public void draw(int x, int y)
{
Canvas.drawPoint(x,y);
}
}

class CarThief implements Drawable
{
public void draw(int x, int y)
{
Car c = steal(Cars.random());
c.drive_to(x,y);
}
}

Both Classes implement Drawable but there is no way to check on two
“Drawable” whether
they share the same semantics.

Regards
Skade
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkgt67EACgkQJA/zY0IIRZZ1sACgmVHN1laF+Xqr72t887Pd+n3J
TwwAniR9ESpQ0gwVGcOA5r4opjn1hLJ+
=GhYL
-----END PGP SIGNATURE-----

Florian, your example is not a fair one; it illustrates an intentional
violation of the semantics, whereas Roger is referring to an
accidental one. In fact, it illustrates the lengths to which one must
go to trigger the problem in Java.

Roger, your question is one that I have shared. I think it’s
mathematically impossible to deny that the less restrictive nature of
duck typing makes it more likely to encounter an inappropriate
object. The question, though, is how much more likely? As in
premature optimization, do we really know that this will be a
problem? Or are we incorrectly assuming it?

People with much more experience with Ruby than I (such as Dave)
report that this is not a problem in practice. I think the minimal
risk here needs to be balanced with the formidable benefits of coding
in such a highly productive language as Ruby.

  • Keith

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Roger A. wrote:

| How do you deal with ducktyping?
| How can anyone assume that just because a method exists that the
| semantics is the same?

Well, if it walks like a duck, and it talks like a duck, it probably is
a duck.

I.e. if a Class or variable reacts to certain methods, it probably is of
the correct type.

| Brush.Draw( x , y )
| vs
| Cowboy.Draw( direction, speed )
|
| The same name and signature, not even close to the same semantic
| meaning.
|
| Doesnt this put an extra burden on the developer, that he has to know
| the exact intention of each and every method?

That’s true of any language. .NET baffles me, for example. :stuck_out_tongue:

| Where in a language that supports ifaces you simply know that the
| methods associated with the interface have a certain meaning.

It’s similar in Ruby (but not quite). Unlike more ‘blue-collar’
languages (not my term! And it is usually used in conjunction with Java,
but it probably applies to .NET as well), Ruby doesn’t try to protect
you. It has some ‘safety’ measures, though.

‘a string’ + 2 Won’t work, as the string is, well, a string, and the 2
is an integer. And you can’t implicitly cast types in Ruby, for example.

| The backside of dynamic typing.
| I got a mail from a newsgroup a few days ago with the title “we once
| overflowed a long at google”
|
| Ok ok, as I said, I get type promotion.
| But what if you assign a “Giraffe” to a property called “Orders” , isnt
| that just as bad or even worse than overflowing a number?

Depends on the scenario, I guess, and what ‘Orders’ is supposed to do.
If it is, for example, an array holding all items in a shopping cart,
there is no issue. If ‘Orders’ is only supposed to contain objects of
the class ‘Fruit’, you are of course in a bit of a pickle. However, the
class ‘Orders’ is supposed to handle that.

Note: I don’t think that data structures like arrays or hashes can
actually overflow. You can create them with arbitrary lengths (subject
to limitations like available memory, obviously).

Ruby’s Array’s aren’t like (I think this is .NET syntax, but feel free
to correct me, it’s been a while) Array ary = Array[9];, where ary can
hold only 10 members.

| If someone say “that should be caught in a unit test” , well so should
| the overflowed long (And Java and .NET can use big integers etc too if
| you need)

Well, this probably more an issue with the developer, than the language,
from what I can see.

| And the thing that I have the hardest time with, how the heck do you
| learn to use someone elses framework / api ?

How did you learn .NET? Same thing, really: Reading documentation, using
tutorials, experimentation.

| in a typed language with decent intellisense I can see what types Im
| supposed to pass in and what I get back.
| One can often understand how to use an API by just looking at the
| intellisense.

NetBeans, Eclipse, and Ruby in Steal (which is built upon visual Studio,
but isn’t free, but has actual IntelliSense™) can do that for you.

It hinges on the documentation provided by the gem / application you use
to tell you what the method expects.

| While I found myself browsing ruby docs back and forth just to see if
| the result of a method would be a string or an object etc.

Well, usually a Ruby object returns what you pass in. So, something that
handles arrays, returns an array. I think. If that is what you mean. :slight_smile:

| So can someone try to convert me or am I forever lost? :stuck_out_tongue:

Hey, doing something that took you 3 months in .NET in 1 week in a
foreign language is a rather strong testimonial, isn’t it?

Though, as Dave Black suggested, you’ll have to try for yourself. Work
with Ruby for a while, and if you like it, you like it, and if you don’t
like it, then you don’t like it. :slight_smile:

In my, admittedly limited experience in using statically typed language
versus Ruby, I don’t need the additional safety or benefits the static
types provide. How ever, you mileage will vary.


Phillip G.
Twitter: twitter.com/cynicalryan
Blog: http://justarubyist.blogspot.com

~ - You know you’ve been hacking too long when…
…you’re trying to get to sleep but can’t because you don’t know the
right VMS logical–you keep typing SHOW LOGICAL SLEEP and never get
anything but: SHOW-S-NOTRAN, no translation for logical name SLEEP
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkgt3pwACgkQbtAgaoJTgL+kfQCfWxaHIIUz65IWBAnzfuJar9vH
pk0AnjFjlIbpgW6F11fblZgMHmf0tOJg
=8an1
-----END PGP SIGNATURE-----

On May 16, 2008, at 12:45 PM, Roger A. wrote:

Ok ok, as I said, I get type promotion.
But what if you assign a “Giraffe” to a property called “Orders” ,
isnt
that just as bad or even worse than overflowing a number?

then you will need a tall box.

a @ http://codeforpeople.com/

On Fri, May 16, 2008 at 5:55 PM, Keith B. [email protected]
wrote:

problem? Or are we incorrectly assuming it?

People with much more experience with Ruby than I (such as Dave)
report that this is not a problem in practice. I think the minimal
risk here needs to be balanced with the formidable benefits of coding
in such a highly productive language as Ruby.

  • Keith

I tend to think that using a RDBMS for data integrity with an overlay
of Ruby is a nice compromise. I’m still anti-unit_test, but then, I’m
not a seasoned programmer and am probably missing the good stuff.

With meta: there’s a very subtle geeky wet dream underlying the whole
concept of meta-programming. I’ll stick around and see what happens,
but I’ll use it sparingly.

Todd

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On May 17, 2008, at 12:55 AM, Keith B. wrote:

Florian, your example is not a fair one; it illustrates an intentional
violation of the semantics, whereas Roger is referring to an
accidental one. In fact, it illustrates the lengths to which one must
go to trigger the problem in Java.

Actually, you don’t have to go that far :). I know, the example is a
artificial.

Actually, i did only add the interface for illustration. A more common
case
would be the assumption that methods of subclasses share
common semantics with methods of superclasses. I had such
a case some time ago, when a fellow student assumed that a method
name was not taken and implemented it on a subclass, causing havoc
in the code calling it :). Granted, this is an indicator that the naming
was too generic, but the language didn’t help a bit.

But the question was:

How can anyone assume that just because a method exists that the
semantics is the same?

This problem is present in both Java and Ruby and none of the
languages helps me much in this. It is much more a question of
programmers discipline, good naming and knowledge of the
ecosystem the software lives in :). Thats perhaps why you don’t
experience it as a big problem. Considering that i assume that
ruby is not the first OOP-Language for many people, they’ve
already got a headstart when it comes to this.

But actually, i can produce a real-world sample for an interesting
semantic
changing behaviour that is much harder to reproduce in Java/C# and
would really be abuse in such languages.

If you know you way around ActiveRecord, calling #find on associated set
of models (e.g. @some_person.friends.find) will not call Array#find but
Friend.find. But if you try inspecting the Object, it will happily
tell you that
it is an Array. (and not some subclass …)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkguItkACgkQJA/zY0IIRZbmsACgujIPlOK7pEM5AeqEEWLf1aYI
mAsAnAjlb3EKVHGFGF/Jn5pBDBVul0AS
=aT3y
-----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On May 17, 2008, at 1:02 AM, ara.t.howard wrote:

On May 16, 2008, at 12:45 PM, Roger A. wrote:

Ok ok, as I said, I get type promotion.
But what if you assign a “Giraffe” to a property called “Orders” ,
isnt
that just as bad or even worse than overflowing a number?

then you will need a tall box.

Pragmatic Programming ;).

Roger, just because variables are not typed doesn’t mean that you can’t
check for Types. Actually, Rubys type-system is quite strong, it doesn’t
allow casts. You can very easily build objekt properties that check for
type or a certain set of methods. Something like:

class Test
attr_accessor :order

def order=(order)
  if order.kind_of?(Giraffe)
    raise Exception.new("We package nearly everything, but

Giraffes???")
end
end
end

So Ruby does typing, but on a different level. It assumes that all
objects are sane and
then gives you the possiblity to check all the information that the
object propagates and
use that for reasoning. See it as a service-based approach. Wouldn’t
be the first time
a service does not do what the name implies ;).

The numbers problem: Conceptually, there is also no such thing as an
“overflowing number”,
in Ruby because Ruby abstracts high enough that you as a Programmer do
not have to to
care about those technical implications. This is a completely
different ballpark ;).

Regards,
Florian G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkguJcMACgkQJA/zY0IIRZbWPQCfWGQIQGaBh1LkaHHqcUCtUbpZ
GiwAn3pWUIjEvwTubAwgodxuyK1oRLZX
=95BN
-----END PGP SIGNATURE-----

Roger A. wrote:

class Test
attr_accessor :order

def order=(order)
  if order.kind_of?(Giraffe)
    raise Exception.new("We package nearly everything, but

Giraffes???")
end
end
end

So is it common practise to do it like this?

I wouldn’t really say it’s “common practice” in Ruby to do a bunch of
kind_of? parameter checks; I haven’t seen it very often, and if it were
the “desirable” thing for a Rubyist to do, the language would do it for
you. As you say, this way adds extra steps just to check some stuff that
only ultimately has the result of increasing the coupling of your code.

Instead, look at it like this: how likely is a Giraffe able to do what
an Order does? If the Giraffe doesn’t quack like an Order, than an
exception is going to be thrown automatically anyway.

Just program in it, and see how often it ever actually bites you. Start
with small things, work your way up. Read other people’s code from time
to time. I myself am from a C# background, and probably I really still
think that way, but I do like Ruby a lot and I find it fun to use even
though my Ruby code doesn’t look as “Ruby” as many of the people’s here.

And do keep in mind that Ruby makes some things quite simple that can be
more of a pain to do in C# – anything involving string manipulation and
regular expressions, for example. And the built-in arrays and hashes
have a ton of functionality and make stuff really succinct (and gets you
away from having to use long nested List<Dictionary<string, Blah>>
stuff, or having to cast all the time with ArrayLists, or whatever). The
language reads well and makes you jump through minimal hoops; the code
you write tends to be shorter and thus easier to digest. It has an
interactive mode that’s really neat, and you can even use it to check
out what methods a given object makes available. The “standard library”
is rich and has a ton of stuff built in. And there’s a lot of
high-quality, free libraries and tools out there that other people have
done.

Where C# trumps it, in my opinion, is in having a ridiculously awesome
IDE integrated with it, and in super easy GUI building capabilities.
(There are other more obvious differences, like performance vs.
cross-platform capabilities.) There are of course Ruby IDEs (including
the SapphireSteel Visual Studio thing or whatever that has Intellisense;
I’m sure the guy will be happy to plug it) and you can of course build
GUIs in Ruby, but again, it’s not about what a language can DO, it’s
about what it makes easy.

So again, just give it a whirl. Outside of whatever your work uses,
there’s no one forcing you to use one language or another. Try them out,
keep an open mind, and go with what feels good.

class Test
attr_accessor :order

def order=(order)
  if order.kind_of?(Giraffe)
    raise Exception.new("We package nearly everything, but

Giraffes???")
end
end
end

So is it common practise to do it like this?
Eg. does active records have this kind of stuff in the generated code
that comes out of “has_many” etc?

Anyway, I think I do buy this.
Preventing the wrong types form beeing used is pretty much the same as
preventing the use of null in C#.
It simply become an extra step in parameter validation.

And thanks everyone for the replies :slight_smile:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On May 17, 2008, at 7:48 AM, Roger A. wrote:

And thanks everyone for the replies :slight_smile:
Yes, ActiveRecord checks for the type of Associations. I would not call
it “common practice” to rely on the type, but as ActiveRecord
maps type Names to Tables, it is desireable to do that.

Regards,
Florian G.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkgunCkACgkQJA/zY0IIRZYn+ACePMafw/w2cezCc8gSzgdzWBgr
uYQAn0RfLmvRqQoztSRSda0FkwHj1V6j
=r4bb
-----END PGP SIGNATURE-----

I wouldn’t really say it’s “common practice” in Ruby to do a bunch of
kind_of? parameter checks;

I am not a good ruby coder but the code I saw, and my own code as well,
rarely uses “.kind_of?” at all

“.is_a?” is much more common from my point of view to be seen in ruby
code

On Sat, May 17, 2008 at 2:43 AM, J. Cooper [email protected] wrote:

Instead, look at it like this: how likely is a Giraffe able to do what
an Order does? If the Giraffe doesn’t quack like an Order, than an
exception is going to be thrown automatically anyway.

Just program in it, and see how often it ever actually bites you. Start
with small things, work your way up.

Good advice.

It brings to mind the experience of learning to ride a bike without
training wheels. There’s even a connection in that learning to ride a
bicycle is learning to deal with dynamic stability.

Of course some can just jump right in, like my 6-year old next door
neighbor, who went right from riding a tricycle to a bike without
benefit of training wheels.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Instead, look at it like this: how likely is a Giraffe able to do what
an Order does? If the Giraffe doesn’t quack like an Order, than an
exception is going to be thrown automatically anyway.

Just program in it, and see how often it ever actually bites you. Start
with small things, work your way up.

Good advice.

This kind of mindset is just asking for things to go wrong…

Lets say that the Giraffe happens to have a few methods that does match
those of an order, so that it manages to introduce incorrect values that
populate through your data before the exception is eventually caught.

(ofcourse a Giraffe is an extreme case, but multiple domain objects can
have attributes that overlap, such as price, name etc)

And once you catch the exception, you have absolutely no clue at all
what have been affected.

Incorrectness should be caught early before it litters your data, or you
will have a seriously hard time debugging.

Just because the language is non strict when it comes to types doesnt
mean you should not care about correctness?

An interesting example of an intentional violation of method semantics
in the Java standard library is the unModifiableXxx() methods in
java.util.Collections. They wrap a collection and override the
mutating methods to throw an exception when they are called.

So someone relying on add() to add an object because that’s what’s
specified in the interface Javadoc would be quite surprised when an
implementation of that interface refused to honor the contract and
threw an exception instead.

  • Keith

On Sun, May 18, 2008 at 12:40 PM, Roger A. [email protected]
wrote:

Incorrectness should be caught early before it litters your data, or you
will have a seriously hard time debugging.

Just because the language is non strict when it comes to types doesnt
mean you should not care about correctness?

The type checking in the popular strongly typed languages like Java
and C++ are actually quite weak in uncovering incorrect code.

They are really about imposing constraints so that code isn’t run
against the wrong data at run-time. Such constraints are necessary in
languages whose implementations determine which method to run by a
type determined at compile time, rather than by using self-describing
runtime information to do method dispatching.

Many errors aren’t found at compile time in these languages, for
example, array bounds errors. It’s very hard to design a static type
system which detects the error in

function foo(array a, int i)
array[i]
end

ary = new Array(10)
foo(ary, 12)

There are certainly less popular languages which attempt this, but
they aren’t widely used. Some consider arrays with different bounds
to be of different types, but this makes it hard to write lots of
things. Others do type inferencing, but these tend to be hard for
mere mortals to understand, at least the ones I’ve seen so far.

So languages like Java, despite being statically typed, defer array
bounds checking to run-time. In the C family of languages, array
bounds violations tend to be unchecked and do lead to mysterious
failures. Of course dynamically typed languages almost invariably do
bounds checking at run-time, sometimes, as in the case of Ruby arrays,
providing dynamically extensible bounds.

As for run-away errors being hard to debug, that’s true, but from
practical experience these tend to be much worse in statically typed
languages where the compiler got fooled by a typecast, or a pointer
alias bug, and branched through a non-existent or wrong virtual
function table, or did a fetch or store outside of the bounds of the
object because it got the type wrong.

Although you might not get an error right away when you confuse a
giraffe with an order, any more than you are guaranteed to in a
statically typed language under all circumstances, experience
indicates that hard to debug problems are actually far less common
than someone only extrapolating experience from static languages would
expect, and are usually much easier to debug when they do occur.

If your concern is correctness, which it should be, then it’s best to
use best practices for writing in dynamic languages, such as TDD/BDD
rather than attempting to mimic techniques from statically typed
languages which are really there to cover the class of errors caused
by a statically typed implementation.

http://talklikeaduck.denhaven2.com/articles/2008/05/18/on-ceremony-and-training-wheels


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

The type checking in the popular strongly typed languages like Java
and C++ are actually quite weak in uncovering incorrect code.

Yes absolutely, static typed languages have a problem finding logical
flaws at compiletime.
But so does Ruby since it doesnt even have compiletime.
So thats a non argument.

If C# cant find logical problems at compile time and
Ruby cant fint logical flaws at compile time either (due to lack of
such)

And you will find the problem at runtime in C#, and likewise in Ruby.

How does that make C# worse than Ruby in that aspect?

They are really about imposing constraints so that code isn’t run
against the wrong data at run-time. Such constraints are necessary in
languages whose implementations determine which method to run by a
type determined at compile time, rather than by using self-describing
runtime information to do method dispatching.

I will still argue that a method name alone is not self-describing.
It will only describe signature but not semantics.
(while I do argue that interfaces carry semantics with them, and that
you have to willingly break that semantics if you implement an interface
method incorrectly)

Many errors aren’t found at compile time in these languages, for
example, array bounds errors. It’s very hard to design a static type
system which detects the error in

function foo(array a, int i)
array[i]
end

ary = new Array(10)
foo(ary, 12)

There are certainly less popular languages which attempt this, but
they aren’t widely used. Some consider arrays with different bounds
to be of different types, but this makes it hard to write lots of
things. Others do type inferencing, but these tend to be hard for
mere mortals to understand, at least the ones I’ve seen so far.

So languages like Java, despite being statically typed, defer array
bounds checking to run-time.

Yes, and Ruby still does runtime checks for everything, so it is still a
non argument.

You are comparing the compile time checks of static languages alone to
the runtime checks of Ruby.
Thats not how it works, static languages have compile time AND runtime
checks.

(And I’m confident that you know that there are list types in other
languages if we need expansion)

As for run-away errors being hard to debug, that’s true, but from
practical experience these tend to be much worse in statically typed
languages where the compiler got fooled by a typecast, or a pointer
alias bug, and branched through a non-existent or wrong virtual
function table, or did a fetch or store outside of the bounds of the
object because it got the type wrong.

Well that’s a bit of a stretch.
You are taking the worst of c and c++ and making it look like its a
major problem in all static typed languages.
(Yes C# have pointers if you like, but they are used once in a lifetime
for most people there)

If your concern is correctness, which it should be, then it’s best to
use best practices for writing in dynamic languages, such as TDD/BDD
rather than attempting to mimic techniques from statically typed
languages which are really there to cover the class of errors caused
by a statically typed implementation.

So you are saying that just because you do TDD you do not apply argument
validation in your API?

Argument validation have nothing to do with static typing, it has to do
with good practice and preventing the consumers of your API from
screwing up badly.

I do practice TDD, but that doesnt make me assume that every consumer of
my code will also do TDD.