Skip to content

Functions

Introduction

All functions in Pineapple are postfix-oriented, meaning that the function names comes after parameter.

In general, there are 5 kinds of functions:

Name Meaning
Nullifunc Function that don't take any parameters.
Monofunc Function that only 1 parameters.
Bifunc Function that only 2 parameters.
Trifunc Function that only 3 parameters.
Polyfunc Function that 4 or more parameters.

Note

  • Function name are always started with a dot. There are no exceptions.

    • For example: .show

    • Not only that, . is also a valid function name!

  • You cannot separate the parameters using comma.

  • Every function definition must start with a def keyword.

  • By convention, parameters names are usually this, that or the.


Nullifunc (0 parameter)

Nullifunc is a function that do not need any parameters, for example:

1
2
3
4
5
6
// Here's how you define a nullifunc
def ().pi -> Number
    return 3.142

// Here's how you call a nullifunc
let x = ().pi

Note

-> Number means that the ().pi function will return a Number type.

Tip

If you want to declare a function that does not return anything, just don't put the arrow symbol.

For example,

1
2
def ().showMyName // no need to put -> here
    pass

Monofunc (1 parameter)

Monofunc is a function that takes only 1 parameter.
Note that the parameter must be at front. For example:

1
2
3
4
5
6
7
8
9
// here's how you declare a monofunc
def (this Number).square -> Number
    return this * this

// here's how you call a monofunc
let x = 99.square

// you can chain it!
let y = 2.square.square.square

Note

this is not a keyword, it is just a variable name!


Bifunc (2 parameters)

Bifunc is a function that takes 2 parameters.
Since you cannot separate parameters with comma, the only way is to put the name in the middle.

For example:

1
2
3
4
5
6
// here's how you define a bifunc
def (this Number).plus(that Number) -> Number
    return this + that

// here's how you call a bifunc
let x = 99.plus(99).plus(22)

Trifunc (3 parameters)

Trifunc is a function that takes 3 parameters. As mentioned before, you cannot separate parameters with comma.
So, you should separate them with an identifier.
For example,

1
2
3
4
5
6
// Here's how you define a trifunc
def (this String).replace(old String with new String) -> String
    pass

// Here's how you call a trifunc
let x = "Hello world".replace("world" with "baby")

Note

with is not a keyword, it is a sub function identifier, it means that you can use any word you like as long as it is a single alphabetical word without spaces!

Just to make it clear, let see another Trifunc example:

1
2
3
4
5
6
// Defining a trifunc
def (this Socket).send(message String to portNumber Integer)
    pass

// Here's how you use it
mySocket.send("Hello world" to 8080)
In this case, to is the sub function identifier.

Why is the sub function identifier necessary?

Pineapple enforces this rules so that every function can be understood better.
Compare the following functions:

1
2
// Javascript
replace("Hello", "el", "lo") // Hmm, is it replacing "el" or "lo" ?
1
2
// Pineapple
"Hello".replace("el" with "lo") // I am very sure it is replacing "el" with "lo"!

There are at least 2 advantages with it:

  • First, you don't need to write too much documentation about your function, as the name already tells the meaning

  • Secondly, when others read your code, they can understand faster


Polyfunc (4 or more parameters)

Polyfunc is a function that takes 4 or more parameters.
It is similar as Trifunc, but it needs 2 or more sub function identifiers.
For example,

1
2
3
4
5
6
// Here's how you define a Polyfunc with 4 parameters
def (this String).replace(startIndex Integer to endIndex Integer with new String) -> String
    pass

// Here's how you call it
let x = "Hello world".replace(0 to 4 with "Hi")

Tips

Sometimes, your function might require a lot of parameters.
In such case, defining functions like this would be dreadful.
So, you should pack those parameters into a single structure.
For example,

1
2
3
4
5
6
7
8
def RequestParam
    :url    String
    :method String
    :body   String
    :schema String

def (this Server).send(that RequestParam)
    pass
Example of usage:
1
2
3
4
5
6
7
let param = RequestParam
    :url    = "192.168.0.0/api/people"
    :method = "POST"
    :body   = '{"name": "Johnny", "age": 999}'
    :schema = "FREE"

myServer.send(param)

Warning

Polyfunc is not implemented yet.


Function chaining

Sometimes you might want to pass a data through multiple functions.

So, instead of using many variables, for example,

1
2
3
4
5
6
7
8
// Using many variables to store intermediate results
def (this Point).distanceTo(that Point) -> Number
    let xDistance = this:x- that:x
    let yDistance = this:y - that:y
    let xDistanceSquared = xDistance.square
    let yDistanceSquared = yDistance.square
    let sum = xDistanceSquared + yDistanceSquared
    let distance = sum.squareRoot

You can use function chaining, as the following,

1
2
3
// Using function chaining
def (this Point).distanceTo(that Point) -> Number
    return ((this:x - that:x).square + (this:y - that:y).square).squareRoot

Multiple line function chaining

If you think you cannot fit all the functions you want to call in a single line, you can also use multiple line function chaining, for example,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def Color
    :red    Number
    :green  Number
    :blue   Number

// multiple line function chaining
def (this Color) == (that Color) -> Boolean
    return  (this:red   == that:red)
        .and(this:green == that:green)
        .and(this:blue  == that:blue)

Warning

When using multiple line function chaining(MLFC), indentation is important. The following are examples of invalid MLFC.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Error
def (this Color) == (that Color) -> Boolean
    return  (this:red   == that:red)
    .and(this:green == that:green) // Should have one indentation here
    .and(this:blue  == that:blue)

// Error
def (this Color) == (that Color) -> Boolean
    return  (this:red   == that:red)
            .and(this:green == that:green) // Too much indentation here
            .and(this:blue  == that:blue)

What's the difference of Pineapple function with named parameters?

Look at the following example to understand the difference.

1
2
# Python
replace(target="Hello world", old="lo", new="wo")
1
2
// Pineapple
"Hello world".replace("lo" with "wo")
Obviously, the Pineapple's version is much more clearer than Python's version.
Moreover, it is also shorter!

Actually, the Pineapple's way of defining function is also known as mixfix function, and that's how it is different from named parameters.

Comments