32

In a discussion about static and instance methods, I always think, that Sqrt() should be a instance method of number types instead of a static method. Why is that? It obviously works on a value.

 // looks wrong to me
 var y = Math.Sqrt(x);
 // looks better to me
 var y = x.Sqrt();

Value types obviously can have instance methods, as in many languages, there is an instance method ToString().

To answer some questions from the comments: Why should 1.Sqrt() not be legal? 1.ToString() is.

Some languages do not allow to have methods on value types, but some languages can. I am talking about these, including Java, ECMAScript, C# and Python (with __str__(self)defined). The same applies to other functions like ceil(), floor() etc.

Den
  • 4,827
  • 2
  • 32
  • 48
Residuum
  • 3,282
  • 28
  • 31
  • 18
    What language are you proposing this in? Would `1.sqrt()` be valid? –  Nov 03 '15 at 14:07
  • 20
    In many languages (e.g. java) doubles are primatives (for performance reasons) so they don't have methods – Richard Tingle Nov 03 '15 at 14:10
  • 1
    in many languages you can also have functions that are not part of any class and I think that would be appropriate. – risingDarkness Nov 03 '15 at 14:17
  • 45
    So numeric types should be bloated with every possible mathematical function that could be applied to them? – D Stanley Nov 03 '15 at 14:24
  • 1
    In Smalltalk it's a method of the numeric types. But Smalltalk is usually the exception, not the rule... – Idan Arye Nov 03 '15 at 14:25
  • 19
    FWIW I think `Sqrt(x)` looks _much_ more natural than `x.Sqrt()` If that means prepending the function with the class in some languages I'm OK with that. If it _were_ an instance method then `x.GetSqrt()` would be more appropriate to indicate that it's _returning_ a value rather than _modifying_ the instance. – D Stanley Nov 03 '15 at 14:28
  • 23
    This question can not be language agnostic in its current form. That's the *root* of the problem. – risingDarkness Nov 03 '15 at 14:41
  • 2
    @DStanley: In reply to your bloating concern: This is very much language dependent. C# (and I think the newest C++) support extension methods, which allow implementers to flag static methods as supporting instance syntax. I imagine this approach would be sufficient to satisfy Residuum's concerns, since his complaint is with caller syntax, rather than performance. Further, plenty of languages implement instance methods as static methods with a hidden `this` argument. – Brian Nov 03 '15 at 14:41
  • 1
    @risingDarkness: I disagree. His question is about a behavior shared by most (though probably not all) languages. – Brian Nov 03 '15 at 14:42
  • 7
    Strictly complete OO languages, where everything is an object, usually behave in the manner that OP thinks is "better". Such langs tend to be duck-typed, so there can be a fair amount of coercion going on. So it makes sense in this context. Though, the question is decidedly not language agnostic because this is a fundamental design choice. –  Nov 03 '15 at 14:48
  • 3
    Regarding whether it's a language-specific or agnostic question: note that some languages have sealed this design decision that primitives cannot have methods, while some other languages have chosen the opposite. These decisions are rarely overturned, ever. In this regard, the answer for some languages would simply be "because they decided not to allow this syntax; that's it", and for the other languages would be "that's an interesting idea; we'll consider it; thanks." – rwong Nov 03 '15 at 14:52
  • 5
    @MichaelT: FWIW, `(1).sqrt()` would be valid in JavaScript (if numbers had a `sqrt` method). Also, somewhat bizarrely, `1..sqrt()`. :-) The only reason `1.sqrt()` wouldn't be is that the `.` is assumed by the parser to be a decimal point, not a property accessor. The second syntax works because the first `.` is the decimal, so the second one *must* be a property accessor. – T.J. Crowder Nov 03 '15 at 18:03
  • 2
    For OOP, objects ideally represent a specific *thing*. Like a `RealNumber` or `Integer` or `Car`. They may also provide methods to get information about or alternative representations of themselves (like `toString()`), and so on. What they don't do is enumerate every possible operation that could be applied to them -- those are *infinite*. Why should `RealNumber` be responsible for [most of this list](https://en.wikipedia.org/wiki/List_of_mathematical_functions), and more? – Matthew Read Nov 03 '15 at 19:52
  • @rwong: There's nor reason Java couldn't have made `(1234.5f).round()` syntactically equivalent to `Float.round(1234.5f)`. Given such a treatment, the effect of changing `(someLong*1.01).round()` to remove the `*1.01` would have been to either yield a syntax error or else yield `someLong` unmodified (depending upon whether `Long` defines `round()`, whereas changing `Math.round(someLong*1.01)` in that way would cause it to silently yield totally bogus results. – supercat Nov 03 '15 at 21:05
  • @supercat surely you would need to implement all those methods in `Number` rather than `Float` and `Long`. Though, in the Java model, this would mean creating ***many*** objects for doing simple math. The early Java gc may have difficulty - especially when it didn't have autoboxing. –  Nov 03 '15 at 21:15
  • @MichaelT: Why would there be boxing? The translation would purely be syntactical. Perhaps they could go in a static `Number` class but things like `round()` really shouldn't use overloading rules that cause invocation of `round()` on a `long` to coerce the argument to `float` and return an `int`; maybe that particular case could be better handled by having static methods `Integer.roundFrom()` and `Long.roundFrom()`, based on the result type. – supercat Nov 03 '15 at 21:28
  • @supercat Float, Long, Double are all subclasses of the abstract Number class. If one has `Float.sqrt()`, and it would make sense for there to be `Double.sqrt()`, then it should probably be in the abstract class instead. However, this all means that simple math operations (like drawing a sine wave) starts creating a multitude of objects that the early Java gc, while good, wasn't great at dealing with. Needless to say, the complexity of the jvm in this case and the Number classes grows significantly. –  Nov 03 '15 at 21:33
  • @MichaelT: Why would it create any objects? The act of invoking a static method doesn't create any objects, and if `Math.sqrt` doesn't create any new objects I don't see why `Double.sqrt()` would. – supercat Nov 03 '15 at 21:36
  • @supercat A static object returning a primitive is one thing. The OP is suggesting that methods be invoked on numeric literals. This implies that those are objects rather than primitives. It isn't about moving `Math.sqrt(double d)` into the `Double` class, but rather making `Number foo = new Double(4.2); System.out.println(foo.sqrt().sin());` work. And *that* implies working with lots more *objects* rather than primitive types. For performance on the early JVM, this had a significant penalty. –  Nov 03 '15 at 21:43
  • @MichaelT: My point was that if a compiler took `double x=4.0, y=x.sqrt();` as another syntax for `double x=4.0; y=whateverClass.sqrt(x);`, performance would be exactly equivalent to the latter because the generated code would be *identical*. – supercat Nov 03 '15 at 21:47
  • 1
    @RichardTingle: Principally, a language could be designed to allow for extension methods, which are still free functions, but called like they would be members (e.g. C# has them). Personally, I dislike them, as they make for highly non-maintainable networks of code. – phresnel Nov 04 '15 at 10:37
  • A related StackOverflow question concerning ruby (where most everything else other than math is an instance method): http://stackoverflow.com/questions/2844526/why-is-sqrt-not-a-method-on-numeric – yoniLavi Nov 04 '15 at 17:53
  • Scott Meyers wrote a very good article a few years ago, named "How Non-Member Functions Improve Encapsulation". It focuses on C++ but the principles apply to any language. www.drdobbs.com/cpp/184401197 – Paul Nov 04 '15 at 21:20
  • 1
    I don't see how `1.Sqrt()` looks better than `Sqrt(1)`. In math take a function `f(x) = sqrt(x)`, how would you write it? Obviously x will be inside `sqrt`. No one writes `2√` – phuclv Nov 05 '15 at 15:16
  • @LưuVĩnhPhúc Yet everyone writes `x.ToString()` instead of `ToString(x)` or `array.length()` instead of `length(array)`. It is a matter of style, and I want to find the rationality for that style. – Residuum Nov 05 '15 at 15:41
  • `x.ToString()` is not a mathematical function. Same as `array.length()`. IMHO it binds more to the object than its value. In math style you may use a variable $L_a$ for the array's length – phuclv Nov 05 '15 at 15:49
  • `#(array)` would be the mathematical equivalent to couting items in a set. An array is not a set, true, but floating point numbers are not rational numbers (or real numbers) neither. It boils down to "why use mathematical notation instead of object oriented programming notation" and is a question of style. – Residuum Nov 05 '15 at 15:57

10 Answers10

65

Suppose we're designing a new language and we want Sqrt to be an instance method. So we look at the double class and begin designing. It obviously has no inputs (other than the instance) and returns a double. We write and test the code. Perfection.

But taking the square root of an integer is valid, too, and we don't want to force everyone to convert to a double just to take a square root. So we move to int and start designing. What does it return? We could return an int and make it work only for perfect squares, or round the result to the nearest int (ignoring the debate about the proper rounding method for now). But what if someone wants a non-integer result? Should we have two methods - one that returns an int and one that returns a double (which is not possible in some languages without changing the name). So we decide that it should return a double. Now we implement. But the implementation is identical to the one we used for double. Do we copy-and-paste? Do we cast the instance to a double and call that instance method? Why not put the logic in a library method that can be accessed from both classes. We'll call the library Math and the function Math.Sqrt.

Why is Math.Sqrt a static function?:

  • Because the implementation is the same regardless of the underlying numeric type
  • Because it does not affect a particular instance (it takes in one value and returns a result)
  • Because numeric types do not depend on that functionality, therefore it makes sense to have it in a separate class

We haven't even addressed other arguments:

  • Should it be named GetSqrt since it returns a new value rather than modifying the instance?
  • What about Square? Abs? Trunc? Log10? Ln? Power? Factorial? Sin? Cos? ArcTan?
D Stanley
  • 1,185
  • 1
  • 7
  • 8
  • 1
    https://en.wikipedia.org/wiki/Integer_square_root how about this for int? – risingDarkness Nov 03 '15 at 14:43
  • 1
    @risingDarkness Sure, that's _one_ possibility. – D Stanley Nov 03 '15 at 14:44
  • 6
    Not to mention the joys of `1.sqrt()` vs `1.1.sqrt()` (ghads, that looks ugly) do they have a common base class? What is the contract for its `sqrt()` method? –  Nov 03 '15 at 14:47
  • 5
    @MichaelT Nice example. It took me four reads to understand what `1.1.Sqrt` represented. Clever. – D Stanley Nov 03 '15 at 14:50
  • 2
    @DStanley `1.1.ToString()` is legal in C#. – Residuum Nov 03 '15 at 14:55
  • @DStanley Ruby is one such language where the numeric type (including the literal) is an object that can be invoked. `1.div(1)` is valid in Ruby (returns `1`) and `1.to_s` is also valid (returns `"1"`). It gets more fun with floating point though. `1.fdiv(1.1)` returns `0.9090...` and `1.1.fdiv(1)` returns `1.1`... however, `1.1.to_s` is a parse error. Joys. –  Nov 03 '15 at 14:55
  • @MichaelT I get that it _can_ be an instance method. But in my opinion it makes more sense to be a shared library ("static" in the OP's context) method. The `int` class is not dependent on it, and it would have to be replicated to all numeric types (or routed back to a shared method, which get us back where we started). – D Stanley Nov 03 '15 at 14:58
  • 2
    @DStanley I'm very much a proponent of the static approach. Just noting that Ruby (an accessible language for many that has a significant smalltalk influence) goes the way of ***everything*** is an object. If you *really* want to have fun, start playing with the open class nature of ruby and redefine the methods on specific instances of the Fixnum class and see how much you can break. –  Nov 03 '15 at 15:00
  • 17
    I'm not really clear from this answer how the static class helps with your main reason. If you have double Sqrt(int) and double Sqrt(double) on your Math class, you have two options: convert the int to a double, then call into the double version, or copy and paste the method with appropriate changes (if any). But those are exactly the same options you described for the instance version. Your other reasoning (particularly your third bullet point) I agree with more. – Ben Aaronson Nov 03 '15 at 17:03
  • 1
    @BenAaronson In C# at least, there is only one static method, and inputs are implicitly converted to `double` (if possible). So you can have one implementation that is applicable to all compatible types. If it were an instance method (and there was no common base type to all numeric types), you'd have to have multiple implementations (or farm it out to a common method outside of the numeric type(s)). – D Stanley Nov 03 '15 at 19:10
  • Very nice explanation. – Robert Harvey Nov 03 '15 at 21:03
  • 1
    "Because it does not affect a particular instance (it takes in one value and returns a result)": A method need not affect an instance: it can also compute a value based on the object it is invoked on and return a new value as the result. – Giorgio Nov 03 '15 at 21:20
  • 1
    @Giorgio It's not _required_, but such methods typically include `Get` in their name to indicate that the result is returned rather than mutating the instance. It's a guideline, not a hard rule, and I grant you that there are exceptions (`Count()`, `Substring()`, etc.). – D Stanley Nov 03 '15 at 21:25
  • 2
    @DStanley: Are you referring to a particular programming language? Java? C#? Some languages are full of pure methods (methods that do not change the instance they are invoked on) that do not follow this convention. Take e.g. Scala. Often these methods are not getters that access a property, but build some new value without mutating their object. As an example, consider the method List.map in Scala. – Giorgio Nov 03 '15 at 21:36
  • 15
    -1 this answer is absurd, what does **any** of this have to do with being static? You're going going to have decide answers to those same questions either way _(and "[with a static function] the implementation is the same" is false, or at least no more true than it would be for instance methods..)_ – BlueRaja - Danny Pflughoeft Nov 03 '15 at 21:52
  • 21
    "The implementation is the same regardless of the underlying numeric type" is utter nonsense. Implementations of the square root function need to differ significantly based on the type they're working with in order not to be horribly inefficient. – R.. GitHub STOP HELPING ICE Nov 04 '15 at 03:37
  • @DStanley So why not have the int cast to a double then call the double's instance method? There's no difference under the hood between implicitly and explicitly casting – Ben Aaronson Nov 04 '15 at 08:27
  • @BenAaronson what would you do for `1.abs()`? Math has `abs(int i)` and `abs(double d)`. Are you proposing putting all of the methods that are in Math into the corresponding wrapper classes? If not, then why not leave it with this simpler approach? –  Nov 04 '15 at 14:43
  • @MichaelT I'm not proposing anything. As I said in my first comment, there are reasons to have these methods static, including the third bullet point in this answer. What I'm questioning is whether the argument in the second paragraph of this answer makes sense as one of those reasons. – Ben Aaronson Nov 04 '15 at 14:48
  • 3
    For the record there are languages in which the Int class extends the Double class, and that also makes this answer complete nonesense! – Pierre Arlaud Nov 04 '15 at 20:41
  • @MichaelT: What should be the effect of `int foo = Math.round(123456789);`? How about `long foo=Math.round(12345678901234L);`? – supercat Feb 13 '16 at 03:22
  • @supercat in Java, each is converted to a `float` and then rounded back to a int. This particular one has some.... lets say nonsensical values returned (as both were changed to `float`, the second one was the `int round(float f)` which returned max_int), however I would contend that you asked it a non-sensical question there. You might want instead to look at `abs` which has four signatures - one for each primitive type. –  Feb 13 '16 at 03:34
  • (key point: a float can hold a Long.MAX_VALUE - so you don't need to widen the long to a double - it can fit in a float) - this is covered in section [5.1.2](https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2) of the JLS) –  Feb 13 '16 at 03:38
  • @MichaelT: If one has something like `Math.round(woozle() * 1.001);` and the because of changing requirements the scaling factor is no longer necessary, would it be visually obvious that omitting the `* 1.001` may totally corrupt the results? IMHO, attempting to round a non-floating-point type should either return the original value unmodified or else yield a compilation error. Further, the rule that considers `long->float` to be a better promotion than `long->double` is IMHO poorly considered. – supercat Feb 13 '16 at 03:50
  • @supercat Long.MAX_VALUE is 2^63. The float can represent up to 2^127. There is no reason to widen it further when there are two methods that both match that signature - it choses the one that requires the least amount of widening. The thing is that int->float is a perfectly acceptable conversion and doesn't make sense as a compilation error. And Math.Round() just sees a float come in - it doesn't know that it was originally an int. You are making arguments for Math.round(int) which... doesn't make sense as a call. –  Feb 13 '16 at 03:54
  • @MichaelT: For every mathematical real number, there is either a unique `float` which best represents it, or else there are two which are equally good; there exists no `double x`, for which there would not be a sensible value `y` for `float y = (float)x;`. Nonetheless, implicit conversions from `double` to `float` were disallowed because they're "lossy". If lossy conversions aren't acceptable, there's no reason a compiler should favor a lossier conversion to a less lossy one. – supercat Feb 13 '16 at 04:08
  • There are design decisions made. Some of them had consequences that are less than ideal. This works in a consistent and reasonable way (not that its a *good* reason - but knowing how it works isn't hard and reasoning from that is possible. –  Feb 13 '16 at 04:12
25

Mathematical operations are often very performance-sensitive. Therefore, we will want to use static methods that can be fully resolved (and optimizied, or inlined) at compile time. Some languages do not offer any mechanism to specify statically dispatched methods. Furthermore, the object model of many languages has considerable memory overhead that is unacceptable for “primitive” types such as double.

A few languages allow us to define functions that use method invocation syntax, but are actually dispatched statically. Extension methods in C# 3.0 or later are an example. Non-virtual methods (e.g. the default for methods in C++) are another case, though C++ does not support methods on primitive types. You could of course create your own wrapper class in C++ that decorates a primitive type with various methods, without any runtime overhead. However, you will have to manually convert values to that wrapper type.

There are a couple of languages that do define methods on their numeric types. These are usually highly dynamic languages where everything is an object. Here, performance is a secondary consideration to conceptual elegance, but those languages are not generally used for number crunching. However, these languages might have an optimizer that can “unbox” operations on primitives.


With the technical considerations out of the way, we can consider whether such a method-based math interface would be a good interface. Two issues arise:

  • mathematical notation is based on operators and functions, not on methods. An expression such as 42.sqrt will appear much more alien to many users than sqrt(42). As a math-heavy user, I'd rather prefer the ability to create my own operators over dot-method-call syntax.
  • the Single Responsibility Principle encourages us to limit the number of operations that are part of a type to the essential operations. Compared with multiplication, you need the square root remarkably rarely. If your language is specifically intended for statistical anlysis, then providing more primitives (such as operations mean, median, variance, std, normalize on numeric lists, or the Gamma function for numbers) can be useful. For a general-purpose language, this just weighs down the interface. Relegating non-essential operations to a separate namespace makes the type more accessible for the majority of users.
amon
  • 132,749
  • 27
  • 279
  • 375
  • Python is a good example of an everything-is-an-object language used for heavy number crunching. NumPy scalars actually have dozens and dozens of methods, but sqrt still isn't one of them. Most of them are things like `transpose` and `mean` that are only there to provide a uniform interface with NumPy arrays, which are the real workhorse data structure. – user2357112 Nov 03 '15 at 18:04
  • 7
    @user2357112: The thing is, NumPy itself is written in a mixture of C and Cython, with some Python glue. Otherwise it could never be as fast as it is. – Kevin Nov 04 '15 at 06:42
  • 1
    I think this answer hits pretty closely to some kind of real-world compromise that has been reached over the years of design. In other news, does it really make sense in .Net to be able to do "Hello World".Max() as the LINQ extensions allows us *AND* makes very visibile in Intellisense. Bonus points: What is the result? Bonus Bonus, what is the result in Unicode...? – Andyz Smith Nov 04 '15 at 15:15
21

It is entirely a choice of language design. It also depends on the underlying implementation of primitive types, and performance considerations due to that.

.NET has just one static Math.Sqrt method that acts on a double and returns a double. Anything else you pass to it must be cast or promoted to a double.

double sqrt2 = Math.Sqrt(2d);

On the other hand, you have Rust which exposes these operations as functions on the types:

let sqrt2 = 2.0f32.sqrt();
let higher = 2.0f32.max(3.0f32);

But Rust also has universal function call syntax (someone mentioned that earlier), so you can choose whatever you like.

let sqrt2 = f32::sqrt(2.0f32);
let higher = f32::max(2.0f32, 3.0f32);
angelsl
  • 326
  • 1
  • 3
  • 1
    It's worth noting that in .NET you can write extension methods, so if you _really_ want to get this implementation to look like `x.Sqrt()`, it can be done. `public static class DoubleExtensions { public static double Sqrt( this double self) { return Math.Sqrt(self); } }` – Zachary Dow Nov 05 '15 at 19:32
  • 1
    Also in **C# 6** it can be just ```Sqrt(x)``` https://msdn.microsoft.com/en-us/library/sf0df423.aspx. – Den Nov 06 '15 at 11:35
15

I would be motivated by the fact that there's a ton of special-purpose math functions, and rather than populate every math type with all (or a random subset) of those functions you put them in a utility class. Otherwise, you'd either pollute your auto-completion tooltip, or you'd force people to always look in two places. (Is sin important enough to be a member of Double, or is it in the Math class along with inbreds like htan and exp1p?)

Another practical reason is that it turns out there may be different ways to implement numerical methods, with different performance and precision trade-offs. Java has Math, and it also has StrictMath.

  • I would hope language designers don't care about auto-complete tooltips. As well, what happens on `Math.<^space>`? That auto-complete tooltip will also be polluted. Inversely, I think your second paragraph is probably one of the better answers here. – Qix - MONICA WAS MISTREATED Sep 29 '16 at 18:53
  • @Qix They do. Although, other people here might call it "making an interface bloated." – Aleksandr Dubinsky Sep 30 '16 at 00:12
6

You have correctly observed that there is a curious symmetry at play here.

Whether I say sqrt(n) or n.sqrt() does not really matter, they both express the same thing and which one you prefer is more a matter of personal taste than anything else.

That is also why there is a strong argument from certain language designers to make the two syntaxes interchangeable. The D programming language already allows this under a feature called Uniform Function Call Syntax. A similar feature has also been proposed for standardization in C++. As Mark Amery points out in the comments, Python allows this too.

This is not without problems. Introducing a fundamental syntax change like this has wide-ranging consequences for existing code and is of course also a topic of controversial discussions among developers who have been trained for decades to think of the the two syntaxes as describing different things.

I guess only time will tell whether the unification of the two is feasible in the long run, but it is definitely an interesting consideration.

ComicSansMS
  • 265
  • 1
  • 5
  • Python already supports both of these syntaxes. Every non-static method takes `self` as its first parameter, and when you call the method as a property of an instance, instead of as a property of the class, the instance gets implicitly passed as the first argument. Hence I can write `"foo".startswith("f")` or `str.startswith("foo", "f")`, and I can write `my_list.append(x)` or `list.append(my_list, x)`. – Mark Amery Nov 05 '15 at 15:14
  • @MarkAmery Good point. This is not quite as drastic as what D or the C++ proposals do, but it fits the general idea. Thanks for pointing out! – ComicSansMS Nov 05 '15 at 15:41
3

In addition to the answer of D Stanley you have to think about polymorphism. Methods like Math.Sqrt should always return the same value to the same input. Making the method static is a good way to make this point clear, since static methods are not overrideable.

You mentioned the ToString()-method. Here you may want to override this method, so the (sub)class is represented in an other way as String as its parent class. So you make it an instance Method.

falx
  • 39
  • 3
2

Well, in Java there is a wrapper for every basic type.
And basic types are not class-types, and have no member-functions.

So, you have the following choices:

  1. Collect all those helper-functions into a pro-forma-class like Math.
  2. Make it a static function on the corresponding wrapper.
  3. Make it a member-function on the corresponding wrapper.
  4. Change the rules of Java.

Let's rule option 4 out, because... Java is Java, and adherents profess to like it that way.

Now, we can also rule out option 3 because while allocating objects is fairly cheap, it isn't free, and doing that over and over again does add up.

Two down, one still to kill: Option 2 is also a bad idea, because it means every function must be implemented for every type, one cannot rely on widening conversion to fill the gaps, or the inconsistencies will really hurt.
And taking a look at java.lang.Math, there are lots of gaps, especially for types smaller than int respective double.

So, in the end the clear victor is option one, collecting them all in one place in a utility-function-class.

Returning to option 4, something in that direction actually happened much later: You can ask the compiler to consider all the static members of any class you want when resolving names for quite a long time now. import static someclass.*;

As an aside, other languages don't have that problem, either because they have no prejudice against free functions (optionally using namespaces) or far fewer small types.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
  • 1
    Consider the joys of implementing the variations on `Math.min()` in all the wrapper types. –  Nov 03 '15 at 22:51
  • I find #4 unconvincing. `Math.sqrt()` was created at the same time as the rest of Java, so when the decision was made to put sqrt() in `Math` there was no historical inertia of Java users who "like it that way". While there isn't much of a problem with `sqrt()`, the overloading behavior of `Math.round()` is atrocious. Being able to use member syntax with values of type `float` and `double` would have avoided that problem. – supercat Feb 13 '16 at 03:18
2

One point that I don't see mentioned explicitly (although amon alludes to it) is that square root can be thought of as a "derived" operation: if the implementation doesn't provide it for us, we can write our own.

Since the question is tagged with language-design, we might consider some language-agnostic description. Although many languages have different philosophies, it is very common across paradigms to use encapsulation to preserve invariants; i.e. to avoid having a value which doesn't behave as its type would suggest.

For example, if we have some implementation of integers using machine words, we probably want to encapsulate the representation somehow (e.g. to prevent bit shifts from changing the sign), but at the same time we still need access to those bits to implement operations like addition.

Some languages may implement this with classes and private methods:

class Int {
    public Int add(Int x) {
      // Do something with the bits
    }
    private List<Boolean> getBits() {
      // ...
    }
}

Some with module systems:

signature INT = sig
  type int
  val add : int -> int -> int
end

structure Word : INT = struct
  datatype int  = (* ... *)
  fun add x y   = (* Do something with the bits *)
  fun getBits x = (* ... *)
end

Some with lexical scope:

(defun getAdder ()
   (let ((getBits (lambda (x) ; ...
         (add     (lambda (x y) ; Do something with the bits
     'add))

And so on. However, none of these mechanisms are needed for implementing square root: it can be implemented using the public interface of a numeric type, and hence it doesn't need access to the encapsulated implementation details.

Hence the location of square root comes down to the philosophy/tastes of the language, and of the library designer. Some may choose to put it "inside" the numeric values (e.g. make it an instance method), some may choose to put it at the same level as the primitive operations (this might mean an instance method, or it might mean living outside the numeric values, but inside the same module/class/namespace, e.g. as a standalone function or static method), some might choose to put it in a collection of "helper" functions, some might choose to delegate it to third-party libraries.

Warbo
  • 1,205
  • 7
  • 11
  • Nothing would prevent a language from allowing a static method to be called either using member syntax (as with C# or vb.net extension methods) or with a variation of member sequence (I would have liked to have seen a double-dot syntax, so as to allow the Intellisense advantages of being able to list only functions that were suitable for the primary argument, but avoid ambiguity with real member operators). – supercat Feb 13 '16 at 03:15
-2

In Java and C# ToString is a method of object, the root of the class hierarchy, so every object will implement the ToString method. For an Integertype it's just natural that the implementation of ToString would work this way.

So you reasoning is wrong. The reason value types implement ToString is not that some people were like: hey let's have a ToString method for Value types. It's because ToString is already there and it's "the most natural" thing to output.

Pieter B
  • 12,867
  • 1
  • 40
  • 65
  • 1
    Of course it is a decision, i.e. the decision to have `object` have a `ToString()` method. That is in your words "some people were like: hey let's have a ToString method for Value types". – Residuum Nov 04 '15 at 13:15
-3

Unlike String.substring, Number.sqrt is not really an attribute of the number but rather a new result based on your number. I do think passing your number to a squaring function is more intuitive.

Moreover, the Math object contains other static members and it makes more sense to bunch them together and use them in a uniform manner.

HaLeiVi
  • 95
  • 3
    Counter example: [BigInteger.pow()](http://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#pow(int)). –  Nov 03 '15 at 21:12