4

Can a mathematical function like sin() be redefined, in Fortran, C or Java code, while preserving the default behavior of other mathematical functions like cos()? Or can another function named sin() but that accepts different argument types be defined in addition to the built-in sin()? I am interested in general features of these languages (I am thinking of applications like the implementation of non-usual number algebras).

I tried to define a sin() function in a Fortran 95 program, but the intrinsic sin() function was called instead… Is there a way around this? what about C and Java?

PS: Here is an example of application: you have some calculation code already written; you realize that it would be useful if all the calculations could yield numbers with uncertainties (like 3.14±0.01). It would be convenient to keep all mathematical expressions (like for instance z = sin(x+2*y)) unmodified in the code, even if x and y are numbers with uncertainties (instead of floats). This is an exemple of why having a sin() function that generalizes the usual sine function is useful.

The reason why I also included in the question the condition that certain functions be not modified is that a custom library that calculates the uncertainty on sin(x) when x has an uncertainty might not implement all the standard functions, so it would be nice to still be able to have access to some standard functions.

These features are present in Python, and this makes using the uncertainties Python module (which I wrote) quite convenient. I would be interested to know better how much of this convenience is due to Python being the language it is, and how convenient a similar uncertainty calculation library written for C, Fortran or Java could be.

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260

6 Answers6

7

There is no problem redefining an intrinsic in Fortran. This won't effect other intrinsics, but of course you won't have access to the intrisic that you have "shadowed". Example code:

module my_subs

contains

function sin (x)
real :: sin
real, intent (in) :: x

sin = x**2

return
end function sin

end module my_subs

program test_sin

use my_subs

implicit none

write (*, *) sin (2.0)

stop

end program test_sin

Output is 4.0

gfortran gives a warning: "'sin' declared at (1) may shadow the intrinsic of the same name. In order to call the intrinsic, explicit INTRINSIC declarations may be required." ifort does not give a warning..

M. S. B.
  • 28,968
  • 2
  • 46
  • 73
  • +1: The Fortran code I had tested did not produce a similar result. I now realize that not defining `sin()` inside a module was the reason. Thanks! – Eric O. Lebigot Nov 14 '11 at 15:52
  • I put your `my_subs` module in a first file `my_subs.f95` and the main program in another program `main.f95`, while at the same time adding `cos(0.)` to it. The `sin()` function was that of `my_subs`, while the `cos()` was the standard one. Is this behavior standard in Fortran? Furthermore, is there a way of calling the original `sin()` function, in these programs? – Eric O. Lebigot Nov 17 '11 at 16:01
5

In C you can use the preprocessor:

#define sin mysin

Then, when you do

sin(x);

you will actually call

mysin(x);

You can also bypass the #include where the sin function is defined and then you can define your own.

In Java, I believe it's enough to write your own implementation in your own package and use that, either by importing your package or qualifying the call:

mypackage.MyClass.sin(x);
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    In C bypassing the `#include` will not make the symbol disappear from linkage, where it will clash with the standard library. – datenwolf Nov 14 '11 at 09:52
  • @datenwolf symbol names are mangled in the linker, so even if it has the same name in the code, I doubt it will have the same name for the linker. – Luchian Grigore Nov 14 '11 at 09:57
  • @datenwolf: Is it always possible to prevent a clash with the standard C library? for example, as far as I understand, Luchian's approach could work with gcc's `-fno-builtin`, no? – Eric O. Lebigot Nov 15 '11 at 09:56
  • @EOL: -fno-builtin just tells the compiler not to replace calls to stdlib functions like sin with optimization paths, but to go the long road through libm. The problem is not compile time (which is when includes are applied), but link time, when the linker will see multiple conflicting instances of the sin symbol defined. There's libm exporting a "sin" symbol, and then there's a object file, also exposing a "sin" symbol; how should the linker be able to decide, which of both to link the calls to "sin" against? The linker sees only the symbol names and does not know about includes used. – datenwolf Nov 15 '11 at 10:04
  • @datenwolf: Thanks for the info about -fno-builtin. Are you implying that there no way to tell the linker not to use libm? – Eric O. Lebigot Nov 15 '11 at 17:44
  • @EOL: You can, of course tell the linker to ignore the standard library, but then you'll of course loose all those functions of the stdlib - it also means your program will lack the runtime support code, which prepares the process before main is called. Actually libm is not linked automatically, so if you use -fno-builtin, you must add -lm explicitly. – datenwolf Nov 15 '11 at 18:09
  • @datenwolf: So the conclusion is basically that one cannot easily redefine only sin() in C, right? You might want to summarize this in an answer; I would +1 it, since you pointed out this interesting linking problem. – Eric O. Lebigot Nov 15 '11 at 18:19
  • 1
    @EOL: Well, you certainly can use a prefix and the preprocessor to "overlay" the identifier at compile time. Why is actually the only way to do this properly. – datenwolf Nov 15 '11 at 20:20
2

In C, if you don't include <math.h> then sin is available as a symbol for use by the program -- as a function or anything else you like. If you do include it, then sin is reserved even as a macro, although in practice you'd probably find that defining it to call your own function will work.

In Java there are no free functions, hence no function sin. java.lang.Math.sin(double) is part of the standard libraries, and so is java.lang.StrictMath.sin(double). There's no way to add a method into an existing class, so you can't replace it. But you can give any other class you do write a method named sin.

I don't know Fortran at all.

The usual way around it (without any more detail what your actual problem is with the standard implementations in those languages): call your function something else.

In all languages, your implementation could provide a way to link against a user-defined version of part or all of the standard libraries (heck, you can user-define the entire implementation, if you want to do the work). This is likely to be the way to go if you want to re-implement sin. In C you'd compile a library to link against, and specify the linker options to use it: libm is a lot like any other library. But you have to bear in mind that the compiler is allowed, if it chooses, to treat sin specially in programs that have #included <math.h>. The compiler is allowed to implement any standard function itself if it feels like it, so the call to sin is not guaranteed to link against the library function sin, it might instead use a compiler builtin. If the CPU has a sin instruction, you might even think it's quite a good idea to avoid the function call.

In Java you could in some cases specify a classloader to supply your version of a class, but I'm not sure whether that will work with classes in java.lang, since that's a magic namespace. You can always poke around inside your implementation (installed JRE, for example), and bear in mind (1) that the sin implementation could (should?) be implemented using native methods; (2) you could easily break something.

There are generally no guarantees as to whether standard functions call each other or not, and if they do then no guarantees whether they'll call the standard version or yours. In practice I think it's unlikely that other standard function will call sin -- likely there's an internal helper function called by both sin and cos (after taking a modulus and applying a phase angle), and tan will not use either of them because tan(x) = sin(x) / cos(x) isn't as accurate or as fast as you can do by other means.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    In C, the sin symbol is still part of the standard library, and redefining it in one's own code will lead to disaster sooner than later at link time. One must never use standard library names for own symbols. Technically you could define it as a static function. But if you really ought to "redefine" standard functions, use a macro to replace all occurances in your code with your selfdefined ones in their own namespace (i.e. with a prefix added to avoid collision). – datenwolf Nov 14 '11 at 09:51
  • 1
    @datenwolf: that's not my understanding of the C rules on "reserved identifiers" (7.1.3). It does not say that all symbols defined in any standard header are reserved for all purposes. It merely says that the standard headers declare/define their own symbols (and of course if that has happened, you can't use them for anything else). There's a difference from C++ here, since in C++ any standard header is allowed to include any other, so any standard header *might* define any symbol from any other, and avoiding the include is no defence. – Steve Jessop Nov 14 '11 at 10:04
  • This is not about headers, it's about symbols at the linkage levels. In C symbol names are not mangled. So when the program gets linked, the linker will see a symbol "sin" coming from the standard library, and a symbol "sin" coming from the program which causes a conflict. If the redefined sin is a static function, then the symbol doesn't get exported, thus avoiding the conflict. But it's a bad practice and you should not do it. This is also not about reserved identifiers, but the way linkers work. – datenwolf Nov 14 '11 at 10:14
  • 1
    @datenwolf: well, if the question is just about the way linkers work, not about the standard, then you need to look at what implementation-specific linker options (if any) will ensure that the library path is searched in a suitable order so that the `sin` symbol from the user library hides the `sin` symbol from the standard library. Anyway, my understanding of the rules on reserved identifiers may be incorrect, since it turns out on experiment that GCC can indeed call standard `sin` whether I include or not. – Steve Jessop Nov 14 '11 at 10:24
  • This has nothing to do about linkage order. Also you seem to forget, that in ANSI-C if a function is not explicitly declared, the compiler implies `int ()(...)` as type. And last but not least `sin` is a GCC builtin, so you'll have to add -fno-builtin. – datenwolf Nov 14 '11 at 13:05
2

You can't replace Math.sin(double) but you can make a MyMath.sin(double) which you can use instead.

import static mypackage.MyMath.sin;
import static java.lang.Math.cos;

// later
double s = sin(d); // uses MyMath.
double c = cos(d); // uses Math.
naught101
  • 18,687
  • 19
  • 90
  • 138
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • +1. I guess you mean "you *can't* replace Math.sin(double)", right? Interesting (I don't know much about Java). – Eric O. Lebigot Nov 14 '11 at 15:54
  • 1
    You can't replace it without using tricks. You can edit the `Math.java` and use your copy instead, or use byte code manipulation to do the same. – Peter Lawrey Nov 14 '11 at 16:09
1

You might want to consider a language that is better suited to the task.
As stated in previous answers, you can somewhat avoid using the built-in sin function, but it is not overriding. For some non-usual number algebra (e.g church numeral system) you might want to think of using a dynamic language like LISP or Scheme.

bakoyaro
  • 2,550
  • 3
  • 36
  • 63
Royi Freifeld
  • 629
  • 2
  • 11
  • 31
  • is there a practical difference between using a self-defined `sin()`, as in the top two answers, and "overriding"? If you're talking about a specific language, you should say so. – naught101 Feb 26 '15 at 02:01
1

In C redefining a function linked in from another compilation unit is between difficult to impossible. It all boils down to the following: When a program is compiled, every imported or exported symbol is listed in a table of symbols. You can look at this table using on GPL systems, therefore Linux objdump -T $EXECUTABLE_OR_BINARYOBJECT, on Unix and Linux nm $EXECUTABLE_OR_BINARYOBJECT

The linker then uses this table to identify the parts to be "glued together". First it reads in the symbol table of each binary and library provided, fills in the table of symbols with where to find them and then links them with the empty slots of symbol imports (I thereby strongly recommend every programmer to read a linkers source code, or better yet, write his own – it's highly instructional).

The standard library, or libm specifically provides the symbol sin, among other things. Now imagine a program where some compilation unit also exports a symbol named sin. The linker has only the symbol names to work with; if a symbol happens to collide, what happens strongly depends on the linker, but what one can be sure of is that it will unlikely be what's desired.

C++ avoids namespace collisions by mangling the symbols. The mangled name contains information about type and namespace. However if in a C++ program two symbols of the same name and type, without or within the same namespace are defined in multiple compilation units, the same problem exists.

Fortran is even older than C. Like in C there are no namespaces, and again only symbol names are used for linking. So the problem is the same, at least for Fortran77.

Objective-C is technically C with a message based object system on top; same linkage rules. Objective-C++ relates to Objective-C as C++ does to C.

In Java each symbol exists in it's class and is thereby surrounded by a namespace. Since classes are tied to compilation units, this also prevents namespace collisions, naturally. But it also makes it next to impossible to redefine things in Java in a straightforward way (one can do crazy things on the bytecode level though).

In Python external functionality is accessed by modules. If you write import spamneggs what actually happens is that the special function __import__ is called and the result stored as variable with the modules name. The type of that variable is module, but technically it's just a reference to a glorified dictionary, similar to classes. If you write

import math

origsin = math.sin()
def mysin(v):
    return origsin(v)

math.sin = mysin

what happens is, that you take a copy of the original math.sin and overwrites math.sin with your redefinition. Since module instances are shared across the interpreter, unless a sandbox is used, this redefines sin in a transparent, nonbreaking way for the whole program. This allows one to choose: Either redefine for the whole program, or use a sandbox to keep things local.

I'm not a as experienced Ruby coder, so I can't tell you about this.

In Lisp and Scheme you can do much cooler things than just redefinition, but everything you do has only local effects without sideeffects. In Haskell it is similar.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Mac OS X does not have objdump, apparently. I guess that `nm` is similar, no (that's what I used under Unix 17 years ago…)? – Eric O. Lebigot Nov 15 '11 at 21:24
  • @EOL: Yes, of course. Silly GNU binutils mistake here. And I have them installed on my Mac, too. – datenwolf Nov 15 '11 at 21:28
  • M. S. B.'s answer uses a Fortran module: can't modules isolate function names in a linker-friendly name (i.e. can they prevent collisions)? – Eric O. Lebigot Nov 15 '11 at 21:31
  • @EOL: That would be module local, nonexported symbols. C has similar, that is global identifiers with static storage modifier, i.e. `static void localsymbol(void)`. As a matter of fact one should hide all but the to be exported symbols using static in C code. It makes the symbol table smaller, allows for better optimization and quicker starting programs (linking is essentially a search problem, if the dynamic linker has to weed through shared objects superfluous symbol tables, this helps not to speed things up). – datenwolf Nov 15 '11 at 21:39
  • Fortran can actually do the same thing as Python's `from module import *`: http://stackoverflow.com/questions/3874585/emulating-namespaces-in-fortran-90. There does not seem to be any problem with linking. Can you confirm and maybe update your answer? – Eric O. Lebigot Nov 22 '11 at 08:35
  • @EOL: I was thinking of Fortran77. – datenwolf Nov 22 '11 at 09:26