Applied Programming/Functions

OverviewEdit

A function is a structuring element grouping statements together, often utilized in a computer program more than once to repeat a task. Without these functions, the alternative to reuse code would be copying it and adapting it to different contexts, which would be a bad idea. Redundant code - repeating code in this case - should be avoided. Using functions usually enhances the comprehensibility and quality of a program. It also lowers the cost for the development and maintenance of the software. Functions have various names in programming languages (e.g., subroutines, routines, procedures, methods, or subprograms).

Let us look at the following code:

print("Program starts")
    
print("Hi Peter")
print("Nice to see you again!")
print("Enjoy our video!")
    
print("Hi Sarah")
print("Nice to see you again!")
print("Enjoy our video!")
    
print("Hi Dominque")
print("Nice to see you again!"
print("Enjoy our video!")
    
Output:
    
''Program starts''
''Hi Peter''
''Nice to see you again!''
''Enjoy our video!''
''Hi Sarah''
''Nice to see you again!''
''Enjoy our video!''
''Hi Dominque''
''Nice to see you again!''
''Enjoy our video!''


Let us have a closer look at the code above. You can see in the code that we are greeting three persons. We use three print statements that are nearly the same; just the name is different. This is what we call redundant code. We are repeating the code three times. This is an example where functions can and should be used to eliminate redundant code.

The following Python code uses a function containing a parameter with the name "name." Redundancy is eliminated and the code is more concise. Take a look:

def greet(name):
    print("Hi " + name)
    print("Nice to see you again!")
    print("Enjoy our video!")
    print("Program starts")
    greet("Peter")         
    greet("Sarah")      
    greet("Dominque") 
   
Output:    
    
''Program starts''
''Hi Peter''
''Nice to see you again!''
''Enjoy our video!''
''Hi Sarah''
''Nice to see you again!''
''Enjoy our video!''
''Hi Dominque''
''Nice to see you again!''
''Enjoy our video!''

In the samples above, the use of functions results in less lines of code, 20% less to be specific. Any further reuse of the function would provide even greater efficiency.

A function in Python is defined by a def statement. The general syntax looks like this:

    def function_name(parameter list):
         statements and the function body

The parameter list consists of none or more parameters. Parameters call the actual data to be used (arguments), if the function employs any. The rest of the function body consists of indented statements. The function body gets executed every time the function is called.

Local and Global Variable Scope in FunctionsEdit

When defined within the function, variable are by default local in scope to the function.

Here's an example:

    def f(): 
        print(s)
    s = "chimichurri"
    f()

Output:

chimichurri

Example:

    def f(): 
        s = "chimichanga"
        print(s)
    f()

Output

chimichanga

Example:

    s = "chimichurri"
    f()
    print(s)

Output:

chimichanga
chimichurri

Example:

    def f(): 
        print(s)
        s = "chimichanga"
        print(s)
    s = "chimichurri" 
    f()
    print(s)

Output:

    UnboundLocalError                         Traceback (most recent call last)
    <ipython-input-25-81b2fbbc4d42> in <module>
         6 
         7 s = "chimichurri"
    ---->8 f()
         9 print(s)

    <ipython-input-25-81b2fbbc4d42> in f()
         1 def f():
    ---->2     print(s)
         3     s = "chimichanga"
         4     print(s)
         5 
    UnboundLocalError: local variable 's' referenced before assignment

If we execute the previous script, we get the error message: UnboundLocalError: local variable 's' referenced before assignment.

The variable 's' is ambiguous in f(), i.e. in the first print in f() the global 's' could be used with the value "chimichurri". After this, we define a local variable s with the assignment s = "chimichanga".

    def f():
        global s
        print(s)
        s = "dog"
        print(s) 
    s = "cat" 
    f()
    print(s)

Output:

cat
dog
dog

We made the variable 's' global inside of the script. Therefore anything we do inside of the function body is done to the global variables outside of it. [1]

Modular ProgrammingEdit

What is it?Edit

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.[2] It can be used in a variety of applications and functions with other components of the system. Similar functions are grouped in the same unit of programming code and separate functions are developed as separate units of code so that the code can be reused by other applications.[3]

Why use it?Edit

The purpose of modular programming is to make it easier to develop and maintain large software programs, by breaking them up into smaller parts. Modular programming usually makes your code easier to read because it means separating it into functions that only deal with one aspect of the overall functionality. It can make your files a lot smaller and easier to understand compared to monolithic code. Software that’s split into distinct modules is also ideal for testing. That’s because tests can be much stricter and more detailed when you test small functions that do less, compared to big functions that do many things. This is especially true if you can only test the outputs of a function, rather than seeing the steps it follows. Separating functions in this way can make it much quicker and easier to find what you’re looking for later.[4]

Modular vs Structured vs Object-OrientedEdit

Modular programming is closely related to structured programming and object-oriented programming, all having the same goal of facilitating construction of large software programs and systems by decomposition into smaller pieces. In more specific terms, modular programming refers to the high-level decomposition of the code of an entire program into pieces: structured programming to the low-level code use of structured control flow, and object-oriented programming to the data use of objects, a kind of data structure.[5]

ModulesEdit

The code is composed of many different code modules that are developed separately. This allows different developers to take on discrete pieces of the system, designing and implementing them without having to understand all of the rest. But to build large programs out of modules effectively, we need to be able to write modules that are correctly isolated from the rest of the program. Rather than have to think about every other part of the program when developing a code module, we need to be able to use local reasoning. That is reasoning about just the module, and the contract it needs to satisfy with respect to the rest of the program. If everyone has done their job, separately developed code modules can be plugged together to form a working program without every developer needing to understand everything done by every other developer in the team. This is the key idea of modular programming.[6]

ParametersEdit

A function or procedure usually needs some information about the environment, in which it has been called. The relationship between the environment and the function involves special variables, which are called parameters. By using these parameters, it's possible to use all kinds of "outside" objects inside of a function. The syntax for how parameters are declared and the semantics for how the arguments are passed to the parameters of the function depends on the programming language.

Very often the terms parameter and argument are used synonymously, but there is a clear difference. Parameters are inside functions or procedures, while arguments are used in procedure calls (i.e., the values passed to the function at run-time).

The evaluation strategy for arguments (i.e., how the arguments from a function call are passed to the parameters of the function) differs between programming languages. The most common evaluation strategies are "call by value" and "call by reference."

SubroutineEdit

What is it?Edit

A subroutine is a sequence of program instructions that performs a specific task, packaged as a unit. This unit can then be used in programs wherever that task should be performed. Subroutines may be defined within programs, or separately in libraries that can be invoked. In different programming languages, a subroutine may be called a routine, subprogram, function, method, or procedure. Technically, these terms all have different definitions. The generic umbrella term 'callable unit' is sometimes used as well.[7]

TypesEdit

There are two types of subroutines: procedures and functions. A procedure is a subroutine that performs a specific task. When the task is complete, the subroutine ends and the main program continues from where it left off. For example, a procedure may be written to reset all the values of an array to zero, or to clear a screen. Meanwhile, a function works in the same way as a procedure, except that it manipulates data and returns a result back to the main program. [8]

Call by valueEdit

The most common strategy is the call-by-value evaluation, sometimes also called pass-by-value. This strategy is used in C and C++, for example. In call-by-value, the argument expression is evaluated, and the result of this evaluation is bound to the corresponding variable in the function. So, if the expression is a variable, its value will be assigned (copied) to the corresponding parameter. This ensures that the variable in the caller's scope will stay unchanged when the function returns. In other words, a copy of the argument passed to the function is made. When any operation is done on the copy, the actual value does not change. It only changes the value of the copy which is made inside the function. Here's an unbiased Python example:

def test(string):
    string = "Python is cool"
    print("Inside function: " + string)

string = "Python"
print("Before function call: " + string)
test(string)
print("After function call: " + string)

Output

Before function call: Python
Inside function: Python is cool
After function call: Python

As you can see, a copy of the argument passed to the function is made. When any operation is done on the copy, the actual value does not change. It only changes the value of the copy which is made inside the function.

Call by referenceEdit

In call-by-reference evaluation, which is also known as pass-by-reference, a function gets an implicit reference to the argument, rather than a copy of its value. As a consequence, the function can modify the argument, i.e. the value of the variable in the caller's scope can be changed. By using Call by Reference we save both computation time and memory space because arguments do not need to be copied. On the other hand, this harbors the disadvantage that variables can be "accidentally" changed in a function call. So, special care has to be taken to "protect" the values, which shouldn't be changed. Many programming languages support call-by-reference, like C or C++, but Perl uses it as default. In ALGOL 60 and COBOL there has been a different concept called call-by-name, which isn't used anymore in modern languages.

Python uses a mechanism, which is known as "Call-by-Object", sometimes also called "Call by Object Reference" or "Call by Sharing". If you pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value. The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all (i.e., they are immutable). It's different, if we pass mutable arguments. They are also passed by object reference, but they can be changed in place within the function. If we pass a list to a function, we have to consider two cases: elements of a list can be changed in place (i.e., the list will be changed even in the caller's scope); if a new list is assigned to the name, the old list will not be affected (i.e., the list in the caller's scope will remain untouched). [9] A Python example:

def add_list(a):
    a.append('world')
    print("Inside function call: " + str(a))

a = ['Hello']
print("Before function call: " + str(a))
add_list(a)
print("After function call: " + str(a))

Output

Before function call: ['Hello']
Inside function call: ['Hello', 'world']
After function call: ['Hello', 'world']

On this reference to the original, the arguments is passed and when any operation is performed on the argument the actual value also changes. It changes the value in both function scope and globally.[10]

Call by resultEdit

Call by value-resultEdit

Call by nameEdit

Call by constant valueEdit

Naming ConventionsEdit

What is it?Edit

A naming convention is a pre-determined set of rules or guidelines used for your program’s variables, functions, etc. They are general rules applied when creating text scripts for software programming. They have many different purposes, such as adding clarity and uniformity to scripts, readability for third-party applications, and functionality in certain languages and applications.[11]

Why they are neededEdit

Common reasons for following a naming convention include: reducing the effort needed to read and understand source code, to enable code reviews to focus on more important issues than arguing over syntax and naming standards, and to enable code quality review tools to focus their reporting mainly on significant issues other than syntax and style preferences.[12]

Common conventionsEdit

Camel case - every word is capitalized except the first. There are no spaces in between words. Example:

exampleVariable = 1
def myFunction():

Pascal case - every word is capitalized. There are no spaces in between words. Example:

Example Variable = 1
def MyFunction():

Snake case - every word is lower case. Words are separated by underscores. Example:

example_variable = 1
def my_function():

Which do I useEdit

C++, Java, and JavaScript typically use camelCase, with PascalCase reserved for libraries and classes. C# primarily uses PascalCase, with camelCase used for parameters. Python uses snake_case for most identifiers. In addition, the following rules apply:

  • Do not start with an underscore (used for technical programming)
  • CONSTANTS IN ALL UPPER CASE (often UPPER_SNAKE_CASE)[13]

ReferencesEdit

  1. https://www.python-course.eu/python3_functions.php
  2. https://press.rebus.community/programmingfundamentals/chapter/modular-programming/
  3. https://www.techopedia.com/definition/25972/modular-programming
  4. https://www.tiny.cloud/blog/modular-programming-principle/#:~:text=Modular%20programming%20at%20Tiny&text=For%20example%3A,Bedrock%20%2D%20Our%20testrunner
  5. Modular Programming
  6. https://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/modules/modular_programming.html
  7. Subroutine
  8. https://www.bbc.co.uk/bitesize/guides/zb33rwx/revision/4
  9. https://www.python-course.eu/python3_passing_arguments.php
  10. https://iq.opengenus.org/pass-by-reference-python/
  11. https://www.techopedia.com/definition/20915/naming-convention-programming
  12. [[w:Naming_convention_(programming)|Naming_convention_(programming)
  13. https://en.wikibooks.org/wiki/Programming_Fundamentals/Identifier_Names