Functions

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.

Notes

Before you continue reading, you should know the following rules:

  • 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:

// Here's how you define a nullifunc
def .pi -> Number
    return 3.142

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

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


Monofunc (1 parameter)

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

// 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

Notes: 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,

// 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)

User-defined operators

In Pineapple, Bifunc is a special type of function, because you can use symbols as the function name. For example,

// Here's how you define a operator bifunc
def (this List{Number}) + (that List{Number}) -> List{Number}
    pass

// Here's how you call it
let x = [1,2,3] + [4,5,6]

Note that pass means that the implementation of the function is temporarily passed. You can think of it as throwing NotImplementedException.


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,

// 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 that 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:

// 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?

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

// Javascript
replace("Hello", "el", "lo") // Hmm, is it replacing "el" or "lo" ?
// 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-identifier.
For example,

// Here's how you define a Polyfunc with 4 parameters
def (this String).replace(startIndex Int to endIndex Int 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,

def RequestParam
    :url    String
    :method String
    :body   String
    :schema String

def (this Server).send(that RequestParam)
    pass

Example of usage:

let param = RequestParam
    :url    = "192.168.0.0/api/people"
    :method = "POST"
    :body   = '{"name": "Johnny", "age": 999}'
    :schema = "FREE"

myServer.send(param)

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

Look at the following example to understand the difference.

# Python
replace(target="Hello world", old="lo", new="wo")
// 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.