Is there a programming language where functions can be declared with different type arguments? - arguments

I've been daydreaming about this language where you can define different functions with the same name but whose arguments are of different type (or length).
Here's a naive example, assuming a C-like syntax.
struct vect {
int x;
int y;
};
struct guy {
struct vect pos;
char *name;
};
struct guy new_guy(vect v, char *name) {
struct guy g;
g.pos = v;
g.name = name;
return g;
}
struct guy new_guy(int x, int y, char *name) {
struct vect v;
v.x = x;
v.y = y;
return new_guy(v, name);
}
int get_x(struct vect v) {
return v.x;
}
int get_x(struct guy g) {
return g.pos.x;
}
The point would be in avoiding having long names like: get_vect_x and get_guy_x, etc. The compiler knows what types we are using to call a function so it shouldn't be a problem to figure out which definition to use.
There could also be different definitions for different number of arguments.

From Wiki:
In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with
different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call,
allowing one function call to perform different tasks depending on context.
wiki link giving definition of function overloading

Java is capable of this, which would lead me to wonder if C++ is (much less experienced with it than Java). Declaring methods of the same name with different parameters or similar parameters different types is supported, even with constructors. This is likely easily implemented in Java because it's a statically typed language. A quick way to check if this is possible is to look at the docs of a particular language's standard libraries for constructors that take different combinations of parameters.

Related

Can I include formulas in a struct somehow?

I am trying to create a struct which uses a formula to automatically create data in one of the struct fields when the other two values are entered.
For example, I want to create a 2D rectangular room with Length and Width which are values that are entered. I would then like to include the formula Area = Length * Width in the struct.
Have tried and just get a syntax error :
syntax error: unexpected =, expecting semicolon or newline or }
// CURRENT CODE
type room struct {
L int
W int
A int
}
// WOULD LIKE IT TO BE
type room struct {
L int
W int
A int = room.L*room.H
}
Since A is invariant, this would be a good fit for a function, not a field.
type room struct {
L int
W int
}
func (r *room) area() int {
return r.L * r.W
}
If you would like to keep A as a Field, you can optionally preform the computation in a constructor.
type room struct {
L int
W int
A int
}
func newRoom(length, width, int) room {
return room{
L: length,
W: width,
A: length * width,
}
}
If you think about what you're after, you'll see that basically your desire to "not add unnecessary code" is really about not writing any code by hand, rather than not executing any code: sure, if the type definition
type room struct {
L int
W int
A int = room.L*room.H
}
could be possible in Go, that would mean the Go compiler would have make arrangements so than any code like this
var r room
r.L = 42
is compiled in a way to implicitly mutate r.A.
In other words, the compiler must make sure that any modification of either L or W fields of any variable of type room in a program would also perform a calculaton and update the field A of each such variable.
This poses several problems:
What if your formula is trickier—like, say, A int = room.L/room.W?
First, given the casual Go rules for zero values of type int,
an innocent declaration var r room would immediately crash the program because of the integer division by zero performed by the code inserted by the compiler to force the invariant being discussed.
Second, even if we would invent a questionable rule of not calculating a formula on mere declarations (which, in Go, are also initializations), the problem would remain: what would happen in the following scenario?
var r room
r.L = 42
As you can see, even if the compiler would not make the program crash on the first line, it would have to arrange for that on the second.
Sure, we could add another questionable rule to sidestep the problem: either somehow "mark" each field as "explicitly set" or require the user to provide an explicit "constructor" for such types "armed" with a "formula".
Either solution stinks in its own way: tracing write field access incurs performance costs (some fields now have a hidden flag which takes up space, and each access of such fields spends extra CPU counts), and having constructors goes again one of the cornerstone principles of the Go design: to have as little magic as possible.
The formula creates a hidden write.
This may not be obvious until you start writing "harder-core" Go programs for tasks it shines at—highly concurrent code with lots of simultaneously working goroutines,—but when you do you're forced to think about shared state and the ways it's mutated and—consequently—on the ways such mutations are synchronized to keep the program correct.
So, let's suppose we protect access to either W or L with a mutex; how would the compiler make sure mutation of A is also proteted given that mutex operations are explicit (that is, a programmer explicitly codes locking/unlocking operations)?
(A problem somewhat related to the previous one.)
What if "the formula" does "interesting things"—such as accessing/mutating external state?
This could be anything from accessing global variables to querying databases to working with a filesystems to exchanges over IPC or via networking protocols.
And this all could be very innocently-looking, like A int = room.L * room.W * getCoefficient() where all the nifty details are hidden in that getCoefficient() call.
Sure, we, again, could work-around this by imposing an arbitrary limit on the compiler to only allow explicit access to the fields of the same enclosing type and only allow them to participate in simple expressions with no function calls or some "whitelisted" subset of them such as math.Abs or whatever.
This clearly reduces the usefulness of the feature while greatly complicating the language.
What if "the formula" has non-linear complexity?
Suppose, the formula is O(N³) with regard to the value of W.
Then setting W on a value to 0 would be processed almost instantly but setting it to 10000 would slow the program down quite noticeably, and both of these outcomes would result form a seemingly not too different statements: r.W = 0 vs r.W = 10000.
This, again, goes agains the principle of having as little magic as possible.
Why would we ony allow such things on struct types and not on arbitrary variables—prodived they are all in the same lexical scope?
This looks like another arbitrary restriction.
And another—supposedly—the most obvious problem is what should happen when the programmer goes like
var r room
r.L = 2 // r.A is now 2×0=0
r.W = 5 // r.A is now 2×5=10
r.A = 42 // The invariant r.A = r.L×r.W is now broken
?
Now you can see that all the problems above may be solved by merily coding what you need, say, with the following approach:
// use "unexported" fields
type room struct {
l int
w int
a int
}
func (r *room) SetL(v int) {
r.l = v
updateArea()
}
func (r *room) SetW(v int) {
r.w = v
updateArea()
}
func (r *room) GetA() int {
return r.a
}
func (r *room) updateArea() {
r.a = r.l * r.w
}
With this approach, you may be crystal-clear about all the issues above.
Remember that the programs are written for humans to read and only then for machines to execute; it's paramount for proper software engeneering to keep the code as much without any magic or intricate hidden dependencies between various parts of of it as possible. Please remember that
Software engineering is what happens to programming
when you add time and other programmers.
© Russ Cox
See more.

Why to use "redundant" keyword "struct" for types in Go?

I am a big fan of Golang, and very pleased to how the syntax of Go is designed. As a part of syntax philosophy, we have a rule as following: omit the things (keywords, characters etc.) if they are not needed actually.
For that reason instead of writing redundant colons:
for ; sum < 1000; {
sum += sum
}
You allowed to simply put:
for sum < 1000 {
sum += sum
}
notice how we omitted redundant semicolons
And there are lots of other cases where syntax is gratefully simplified.
But what about struct when we define type?
type Person struct {
name string
}
Why do we need to put struct keyword here?
Keywords are to determine intention, to clarify the exact choice of available options so a compiler knows how to do his job properly.
Will it be unclear and ambiguous if we simply put:
type Person {
name string
}
??
I believe there is a meaning for struct in the examples above
because compiler fails when type defined without struct keyword.
Please, explain me (and provide links) what else we can use instead of struct when we define some type.
Please, list available options from which we want to clarify to a compiler that things in curly brackets after type name are exactly parts of a struct and not something else (what else?).
Thanks.
It's not redundant. You can make types from existing types:
type MyType int
type MyType string
Or interfaces:
type Stringer interface {
String() string
}
This is covered in the Go tour and in the spec.
Types (may) not only appear in type declarations, but in countless other places, for example in function declarations.
Structs may be "used" anonymously, without creating a named type for them. For example, the following declaration is valid:
func GetPoint() struct{ x, y int } {
return struct{ x, y int }{1, 2}
}
Without having to use the struct keyword, a parsing ambiguity would arise in multiple uses. Let's say we want to create a function which returns an empty struct:
func GetEmpty() struct{} {
return struct{}{}
}
How would this look like without the struct keyword?
func GetEmpty2() {} {
return {}{}
}
Now if you're the compiler, what would you make out of this? Is this a function with the same signature as GetEmpty()? Or is this a function without a return value and an empty body (func GetEmpty2() {}) followed by a block which contains a return statement? The return statement would be another ambiguity, as it may return nothing which is followed by 2 empty blocks, or it may return an empty struct value which is followed by an empty block...
Now to avoid parsing ambiguity, we have to use the struct keyword when specifying struct types elsewhere (outside of type declarations), then why make it optional or disallow it in type declarations?
I think a consistent syntax is more important than grabbing all chances to reduce the language (syntax) to the minimum possible. That hurts readability big time. The for loop example you mentioned is not really a simplification, but rather the usage of different forms of the for loop.

C++11 Multiline lambdas can deduce intrinsic types?

I use C++11 lambdas quite a lot, and I've often run into compile errors on multiline lambdas because I forgot to add the return type, as is expected, but I recently ran into one example that doesn't have this issue. It looks something like this:
auto testLambda = [](bool arg1, bool arg2)
{
if (arg1)
{
if (!arg2)
{
return false;
}
return true;
}
return false;
};
This compiles just fine even though there's no return type specified. Is this just Visual Studio being dumb and allowing something it shouldn't, or can lambdas just always deduce intrinsic types?
I tried this with return values of all ints or floating point values and it also compiled just fine. I just found this to be really surprising so I wanted to be absolutely sure how it works before I start making assumptions and omitting return types that might break later on.
Lambdas follow the same template deduction rules as auto-returning functions:
Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.
For auto-returning functions, the parameter P is obtained as follows: in T, the declared return type of the function that includes auto, every occurrence of auto is replaced with an imaginary type template parameter U. The argument A is the expression of the return statement, and if the return statement has no operand, A is void(). After deduction of U from P and A following the rules described above, the deduced U is substituted into T to get the actual return type:
auto f() { return 42; } // P = auto, A = 42:
// deduced U = int, the return type of f is int
If such function has multiple return statements, the deduction is performed for each return statement. All the resulting types must be the same and become the actual return type.
If such function has no return statement, A is void() when deducing.
Note: the meaning of decltype(auto) placeholder in variable and function declarations does not use template argument deduction.

std::function, template parameter T(X)

I'm wondering if anyone can please explain how, given types T and X, std::function takes T(X) as a template parameter.
int(double) looks like the usual cast from double to int, so how is std::function parsing it as distinct types?
I did search but didn't find anything that specifically addresses this question. Thanks!
It can use partial template specialization. Look at this:
template <typename T>
class Func;
template <typename R, typename... Args>
class Func<R(Args...)>
{
public:
Func(R(*fptr)(Args...)) {/*do something with fptr*/}
};
This class takes a single template parameter. But unless it matches R(Args...) (i.e. a function type returning R and taking zero or more args), there wont be a definition for the class.
int main() { Func<int> f; }
// error: aggregate 'Func<int> f' has incomplete type and cannot be defined
.
int func(double a) { return a+2; }
int main() { Func<int(double)> f = func; }
// ok
The specialization can now operate on R and Args to do its magic.
Note that int(double) is a function type. Since you cannot create raw function objects, you don't usually see this syntax outside the template world. If T is int(double) then T* is a function pointer just like int(*)(double).

Why create go types based on other?

what is the purpose of defining new types in go:
type NewType OldType
since NewType have only methods declarations, so:
var x NewType
can store also OldType 'objects'. Are there any advantages?
The reason behind naming types in general is fairly straightforward, and is much the same in most languages - being able to name complex types, like:
type Person struct{
name String
age uint8
}
However, naming a type like you described, which I'll call "type aliasing" (not sure if this is used by anyone else, but it's the term I tend to use), doesn't give you the above-mentioned advantage. What it does give you, however, is the ability to add methods to existing types. Go disallows you from adding methods to existing types that you did not define yourself (ie, built-in types or types defined in other packages), so aliasing allows you to pretend that you did define them yourself, and thus add methods to them. Another good way to think about it is like a much more concise version of creating a wrapper type (as you would in an OO language like Java, for example).
So, let's say that I wanted to be able use integers as errors. In Go, the error interface simply requires a method called "Error" which returns a string. Using type aliasing, I could do:
type errorCode int
func (e errorCode) Error() string {
return fmt.Sprintf("%d", e)
}
...and I could use integer error codes. By contrast, if I tried the following, I would get an error:
func (e int) Error() string {
return fmt.Sprintf("%d", e)
}
To demonstrate, check out this implementation:
http://play.golang.org/p/9NO6Lcdsbq
Just to clarify (because my use of the word "alias" may be misleading), two types which are otherwise equivalent (for example, int and errorCode in the above example) are not interchangeable. The Go type system treats them as fundamentally different types, although you may be able to type-cast between them.
The Go Programming Language Specification
Types
A type determines the set of values and operations specific to values
of that type.
You want identify a specific set of values and operations.
For example,
package main
import "fmt"
type Coordinate float64
type Point struct {
x, y Coordinate
}
func (p *Point) Move(dx, dy Coordinate) {
p.x += dx
p.y += dy
}
func main() {
var p = Point{3.14159, 2.718}
fmt.Println(p)
p.Move(-1, +1)
fmt.Println(p)
}
Output:
{3.14159 2.718}
{2.14159 3.718}

Resources