• Mindscape ๐Ÿ”ฅ
    • Playlist ๐ŸŽง
  • Algorithm

    • 1018๋ฒˆ: ์ฒด์ŠคํŒ ๋‹ค์‹œ ์น ํ•˜๊ธฐ
    • 1966๋ฒˆ: ํ”„๋ฆฐํ„ฐ ํ
    • Python ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํŒ
    • C++ std::vector ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ
    • Vim ์‚ฌ์šฉ ๋งค๋‰ด์–ผ
  • Ubuntu

    • ๋ฆฌ๋ˆ…์Šค ์šฐ๋ถ„ํˆฌ GRUB ํฐํŠธ ๋ณ€๊ฒฝ
    • ์šฐ๋ถ„ํˆฌ ์ด๋ฏธ์ง€ ๋น„๋””์˜ค ์ธ๋„ค์ผ(๋ฏธ๋ฆฌ๋ณด๊ธฐ) ์•ˆ ๋ณด์ž„ ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Wine ํ™˜๊ฒฝ์—์„œ ์นด์นด์˜คํ†ก ์‹คํ–‰ ์‹œ explorer.exe ๋œจ์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฒ•
    • ์šฐ๋ถ„ํˆฌ Wine ์นด์นด์˜คํ†ก ์‚ฌ์ง„ ์ด๋ฏธ์ง€ ์Šคํฌ๋ฆฐ์ƒท ๋ถ™์—ฌ๋„ฃ๊ธฐ
    • Wine ์นด์นด์˜คํ†ก ์ด๋ชจ์ง€ ๊นจ์ง ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Ubuntu ์œˆ๋„์šฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋„๊ธฐ
  • Wellness

    • ์ฐจ์ „์žํ”ผ (Psyllium Husk)
    • ์—‘์ŠคํŠธ๋ผ ๋ฒ„์ง„ ์˜ฌ๋ฆฌ๋ธŒ์œ  (Extra Virgin Olive Oil)
    • ์ž๊ฐ€๋น„๊ฐ•์„ธ์ฒ™ (Nasal Irrigation)
    • QCY HT08 (MeloBuds Pro Plus)
    • ์ฝ˜์„œํƒ€ (Concerta)
    • ์ธ๋ฐ๋†€ (Inderal)
    • ์„คํŠธ๋ž„๋ฆฐ (Sertraline)
    • ๋ฉœ๋ผํ† ๋‹Œ (Melatonin)
    • ์น˜๊ฒฝ๋ถ€ ๋งˆ๋ชจ์ฆ
    • ๋ฐ”๋ฒจ ์Šค์ฟผํŠธ (Barbell Squat)
  • Humanities

    • Nordvik, Russia
    • North Sentinel Island
    • ๋กฑ๊ณ ๋กฑ๊ณ (Rongorongo)
    • ๋ฐ”๋กœํฌ ์Œ์•… (Baroque Music)
  • Design

    • ๊ตฌ๊ธ€์˜ ์•„์ด์ฝ˜ ๋Œ€๊ฐœํŽธ โ€” 6๋…„ ๋งŒ์˜ ์‹ค์ˆ˜ ์ธ์ •
    • ์ œ๋Ÿด๋“œ ์  ํƒ€ โ€” ๋Ÿญ์…”๋ฆฌ ์Šคํฌ์ธ  ์›Œ์น˜์˜ ์ฐฝ์‹œ์ž
    • ๋ฐ”์šฐํ•˜์šฐ์Šค โ€” ํ˜„๋Œ€ ๋””์ž์ธ์˜ ์›์ 
  • Brands

    • NOMOS Glashรผtte
    • Frรฉdรฉrique Constant
    • KZ (Knowledge Zenith)
    • ์—์ŠคํŠธ๋ผ (AESTURA)
    • JINHAO (้‡‘่ฑช)
    • Herman Miller
    • ๋ฐ์Šค์ปค (DESKER)
    • ๋ฌด์‹ ์‚ฌ ์Šคํƒ ๋‹ค๋“œ (Musinsa Standard)
  • Finance

    • ํ˜„๋Œ€์นด๋“œ ZERO โ€” Edition2 vs Edition3 ๋น„๊ต
    • ์‹ ํ•œ์นด๋“œ ์ฒ˜์Œ
    • S&P 500 ETF ํˆฌ์ž ๊ฐ€์ด๋“œ
    • ํŒŒํ‚นํ†ต์žฅ vs CMA ํ†ต์žฅ
    • ๋ฒ„ํฌ์…” ํ•ด์„œ์›จ์ด (Berkshire Hathaway)
    • ๋น„ํŠธ์ฝ”์ธ(Bitcoin)
  • Products

    • ์˜ค๋””์˜ค ์ธํ„ฐํŽ˜์ด์Šค (Audio Interface)
    • ์ฟ ๋ฃจํ† ๊ฐ€ (KURUTOGA)
    • CX31993 DAC ๋™๊ธ€
    • ํด๋ Œ์ง• ๋ฐ€ํฌ (Cleansing Milk)
    • ํ”ผ์ ฏ ํ† ์ด (Fidget Toy)
    • ThinkPad
  • Programming Languages

    • 8.0. Statement Level Control Structures
    • 8. Subprogram
    • 9. Implementing Subprogram
    • 10.1. Abstract Data Types and Encapsulation Constructs
    • 10.2. Support for Object Oriented Programming
    • 11. Concurrency
    • 12. FPL (1)
    • 13. FPL (2)
    • 14. Exception Handling and Event Handling
    • Final Exam

8. Subprogram

์ž‘์„ฑ 2026. 6. 12.ยท์ˆ˜์ • 2026. 6. 12.

Subprogram

  • Abstraction in programming languages

    • Data abstraction (i.e, Record type)
    • Process abstraction
  • In form of subprogram

    • Reuse โ†’ savings, primarily memory space and coding time
    • Abstraction: details are replaced by subprogram calling
    • โ†’ hiding the low-level details
    • โ†’ increases the readability
  • Closely related to method of OOP

  • Difference: way they are called and associations with class

  • There are various forms of the subprogram in programming languages

//C
int add(int a, int b) {
    return a + b;
}
//Java
public class Main {
    public static int add(int a, int b) {
        return a + b;
    }
}
#Python
def add(a, b):
    return a + b
//Javascript
function add(a, b) {
    return a + b;
}
//Swift
func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}
//Rust
fn add(a: i32, b: i32) -> i32 {
    a + b
}
//Ruby
def add(a, b)
    a + b
end
//Haskell
add :: Int -> Int -> Int
add a b = a + b

Today's Contents

  • Fundamentals of subprograms
  • Design issues
  • Local referencing environment
  • Parameter-passing methods
  • Parameter that are subprograms
  • Indirectly called subprograms
  • Overloaded subprograms
  • Generic subprograms
  • Design issues for functions
  • User-defined overloaded operators
  • Closures
  • Coroutines

Fundamentals of subprograms

  • General characteristics
    • Single entry point
    • ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ์€ ํ•ญ์ƒ ํ•˜๋‚˜์˜ ์ง„์ž…์ ์—์„œ ์‹คํ–‰์„ ์‹œ์ž‘ํ•จ
    • One subprogram in execution
    • ํ˜ธ์ถœ ์‹œ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ํ™œ์„ฑ ์ƒํƒœ
    • Control return to the caller after termination
    • Most subprograms have names (ํ•จ์ˆ˜ ์ด๋ฆ„์„ ํ†ตํ•ด ํ˜ธ์ถœ)
    • Except: anonymous subprograms in C# and Python
//C#
Func<int, int, int> add = (a, b) => a + b;
#Python
add = lambda a, b: a + b
  • Alternatives 1(coroutines): ํ˜‘๋™ ๋ฃจํ‹ด, ์ฆ‰ ์ž‘์—… ๊ฐ„ ์ „ํ™˜์ด ๋ช…์‹œ์ , ํ•œ ๋ฃจํ‹ด์ด ๋‹ค๋ฅธ ๋ฃจํ‹ด์—๊ฒŒ ์ œ์–ด๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉฐ ๋Œ์•„๊ฐ€๋ฉฐ ์‹คํ–‰

  • Alternatives 2(concurrent): ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๋™์‹œ์— ์‹คํ–‰๋จ (๋…ผ๋ฆฌ์ ์œผ๋กœ ๋˜๋Š” ์‹ค์ œ๋กœ), ๋™์‹œ ์‹คํ–‰์„ ์ง€ํ–ฅ

  • Basic definitions

    • Subprogram definition describe Interface and actions
    • Subprogram is active after subprogram call
    • Two kinds of subprograms: procedure and function
    • Subprogram header
      • Specifies that the following syntactic unit is a subprogram definition
      • Provides a name
      • Specify a list of parameters (optional)
    • Body contains actions
[Python]
def adder (parameters):
    bodyโ€ฆ
[C]
void adder (parameters){
    bodyโ€ฆ.
}
ํ•ญ๋ชฉ์„ค๋ช…
Subprogramํ•˜๋‚˜์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ๋ธ”๋ก์œผ๋กœ, ํ˜ธ์ถœ๋˜๋ฉด ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰
Subprogram Definition์ธํ„ฐํŽ˜์ด์Šค(์ด๋ฆ„, ๋งค๊ฐœ๋ณ€์ˆ˜)์™€ ๋™์ž‘(๋‚ด์šฉ)์„ ๊ธฐ์ˆ 
ํ™œ์„ฑ ์‹œ์ ํ˜ธ์ถœ(Call)์ด ๋ฐœ์ƒํ•œ ํ›„์— ํ™œ์„ฑ(active) ์ƒํƒœ๊ฐ€ ๋จ
์ข…๋ฅ˜๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์œ ํ˜•: Procedure์™€ Function
Header (ํ—ค๋”)์ด ์ฝ”๋“œ ๋ธ”๋ก์ด subprogram์ž„์„ ๋ช…์‹œํ•˜๋ฉฐ, ์ด๋ฆ„๊ณผ (์˜ต์…˜) ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธ
Body (๋ณธ๋ฌธ)์‹ค์ œ ์ˆ˜ํ–‰ํ•  ๋™์ž‘์„ ์ •์˜
  • Basic definitions
    • [Python] def statement can be executed
    • Assign name to function body (์ด๋ฆ„์„ ํ•จ์ˆ˜ ๋ณธ์ฒด์— ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Œ)
    • No need to declare in advance, declare and use when needed
    • ํ•จ์ˆ˜๋Š” ์ผ๊ธ‰ ๊ฐ์ฒด(first-class citizen): ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ค„์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธ
if condition:
    def add(a, b):
        return a + b
    operation = add        # ๋ณ€์ˆ˜์— ์ €์žฅ
    print(operation(2, 3)) # ์ธ์ž๋กœ ์ „๋‹ฌ, ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์‚ฌ์šฉ, ๊ฒฐ๊ณผ: 5

def fun(x):
    return x + 1
else:
    def fun(x):
        return x - 1

print(fun(3))
# ์‹คํ–‰ ์ค‘ ์–ด๋–ค fun์ด ์ •์˜๋˜๋Š”์ง€๊ฐ€ ๊ฒฐ์ •๋จ
  • Basic definitions
    • [Ruby] Ruby์—์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๊ฐ์ฒด์ด๊ณ , ๋ฉ”์„œ๋“œ๋„ ์˜ˆ์™ธ๊ฐ€ ์•„๋‹˜
    • Can also be defined outside class definitions (ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ๋„ ๋ฉ”์„œ๋“œ ์ •์˜ ๊ฐ€๋Šฅ)
    • Considered as method of root object (Object) (์ด ๊ฒฝ์šฐ Object ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๊ฐ€ ๋จ)
    • Called as if function in C-based (C ์–ธ์–ด ์Šคํƒ€์ผ์ฒ˜๋Ÿผ ํ•จ์ˆ˜ ํ˜ธ์ถœํ•˜๋“ฏ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ)
def greet(name)
    puts "Hello, #{name}"
end

greet("Ruby") # Object์˜ ๋ฉ”์„œ๋“œ๋กœ ํ˜ธ์ถœ๋จ
  • ํ•จ์ˆ˜๋ผ๋Š” ๊ฐœ๋…์ด ์—†์Œ

  • ์ „๋ถ€ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ

  • Basic definitions

    • [Lua] Lua๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ’(value)์œผ๋กœ ์ทจ๊ธ‰
    • Nameless function
    • ํ•จ์ˆ˜๋Š” ์ด๋ฆ„ ์—†๋Š” ๋ฆฌํ„ฐ๋Ÿด(function literal)
function(x) return x * x * x end
  • Function can be assigned to variable
  • ํ•จ์ˆ˜๋Š” ๋ณ€์ˆ˜์— ํ• ๋‹น๋˜๊ณ , ์ธ์ž๋กœ ์ „๋‹ฌ๋˜๋ฉฐ, ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋  ์ˆ˜ ์žˆ์Œ
  • ํ•จ์ˆ˜ ์ •์˜์™€ ํ• ๋‹น์€ ๋™์ผํ•œ ์˜๋ฏธ (์ •์˜ ์ž์ฒด๊ฐ€ expression)
function cube(x) return x * x * x end
cube = function (x) return x * x * x end
  • Python: ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์ง€๋งŒ def๋Š” statement
  • Ruby: ํ•จ์ˆ˜ ์—†์Œ โ†’ ์ „๋ถ€ "๋ฉ”์„œ๋“œ (๊ฐ์ฒด ์†Œ์†)"
  • Lua: ํ•จ์ˆ˜๋Š” ์™„์ „ํ•œ ๊ฐ’ (expression ๊ธฐ๋ฐ˜)
ํ•ญ๋ชฉPythonLuaRuby
ํ•จ์ˆ˜ ์กด์žฌ์žˆ์Œ์žˆ์Œ์—†์Œ (๋ฉ”์„œ๋“œ๋งŒ)
ํ•จ์ˆ˜ = ๊ฐ’Oโ—Ž (๋” ๊ฐ•ํ•จ)โ–ณ (Method object๋กœ๋Š” ๊ฐ€๋Šฅ)
์ •์˜ ๋ฐฉ์‹statementexpression-
์†Œ์†๋…๋ฆฝ๋…๋ฆฝํ•ญ์ƒ ๊ฐ์ฒด์— ์†ํ•จ
ํ˜ธ์ถœ ๋ฐฉ์‹f()f()๊ฐ์ฒด.method
  • Basic definitions

    • Protocol of a subprogram: parameter profile + return type
    • Parameter profile: number, order, and types
    • ์ด ์ •๋ณด๋ฅผ ํ†ตํ•ด ์ปดํŒŒ์ผ๋Ÿฌ๋‚˜ ํ˜ธ์ถœ์ž๊ฐ€ subprogram์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ๋‹จ
    • Declarations provide the subprogram's protocol but do not include their bodies
    • Declarations are needed for static type checking
    • Definition includes actual implementations
  • Two ways to access to values:

    • Direct access to nonlocal variables
    • Parameter passing (more flexible)
  • Two ways to access to values:

    • Direct access to nonlocal variables
      • Extensive access to nonlocals can reduce reliability
      • ์™ธ๋ถ€ ์ƒํƒœ์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ์žฌ์‚ฌ์šฉ์„ฑ, ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ, ๋””๋ฒ„๊น… ๋‚œ์ด๋„ ์ฆ๊ฐ€
      • ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋ฉด side effect ๋ฐœ์ƒ ์œ„ํ—˜ ์žˆ์Œ
      • Changing nonlocals and class variables
      • Can make side effect (should be avoided)
      • Reliable problem
      • Functional language does not have mutable data
      • Unable to change memory
  • Two ways to access to values:

    • Parameter passing (more flexible)
      • ๋” ์œ ์—ฐํ•˜๊ณ  ์•ˆ์ „ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹
      • ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ, ์™ธ๋ถ€ ์ƒํƒœ์™€์˜ ์˜์กด์„ ์ค„์ž„
      • ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ํ•จ์ˆ˜์˜ ๋™์ž‘์„ ์ž…๋ ฅ์—๋งŒ ์˜์กดํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
  • Parameters

    • Transmit computations
    • Name of subprogram is used as parameter
    • ๋‹ค๋ฅธ ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ(ํ•จ์ˆ˜)์˜ ์ด๋ฆ„์„ ์ธ์ž๋กœ ์ „๋‹ฌํ•ด์„œ, ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœ๋˜๋„๋ก ํ•จ
# Python
def square(x):
    return x * x

def compute_and_print(func, value):
    print(func(value))

compute_and_print(square, 5) # โ†’ 25
# Ruby
def square(x)
    x * x
end

def compute(func, value)
    func.call(value)
end

compute(method(:square), 5) # โ†’ 25, square ๋ฉ”์„œ๋“œ๋ฅผ Method ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜
-- Lua
function square(x)
    return x * x
end

function compute(func, value)
    print(func(value))
end

compute(square, 5) -- โ†’ 25
  • Parameters (Python)
    • Formal parameter
      • Parameters in header
      • Thought of as dummy (ํ˜ธ์ถœ ์‹œ ์ „๋‹ฌ๋  ๊ฐ’์˜ "์ž๋ฆฌ๋งŒ ์ฐจ์ง€ํ•˜๋Š” ๋ณ€์ˆ˜")
def greet(name): # โ† 'name'์€ formal parameter
    print("Hello,", name)
  • Actual parameter
    • List of parameters in subprogram call statements
    • ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ์‹ค์ œ๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฐ’
    • ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, ์ด ๊ฐ’๋“ค์ด formal parameter์— ๋ฐ”์ธ๋”ฉ๋จ
greet("Alice") # โ† "Alice"๊ฐ€ actual parameter
  • Parameters (Python)
    • Positional parameter
      • Binding of actual parameters to formal parametersโ€”is done by position
def subtract(a, b):
    return a - b

print(subtract(10, 3)) # a=10, b=3 โ†’ ๊ฒฐ๊ณผ: 7
  • Keyword parameter
    • Binding of actual parameters to formal parametersโ€”is done by name
print(subtract(b=3, a=10)) # ๊ฒฐ๊ณผ: 7
  • [Mix of position and keyword]
sumer(my_length, sum = my_sum, list = my_array)
  • Parameters (Python)
    • Default value
      • Used if no actual parameter is passed to the formal parameter
def compute_pay(income, exemptions = 1, tax_rate)
  • Absent actual parameter
    • Skip (exemptions)
pay = compute_pay(20000.0, tax_rate = 0.15)
  • Parameters (C++)
    • No keyword parameter
    • Default parameter must appear last
float compute_pay(float income, float tax_rate, int exemptions = 1)
pay = compute_pay(20000.0, 0.15);
  • If there is no default

    • the number of formal and actual parameters should be the same
  • Parameters (C#)

    • Variable number of parameters (same type)
    • params (์—ฌ๋Ÿฌ ๊ฐœ ์ธ์ž๋ฅผ ๋ฐ›์•„์„œ ๋ฐฐ์—ด๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ)
      • ๋ฐ˜๋“œ์‹œ ๋งˆ์ง€๋ง‰ ํŒŒ๋ผ๋ฏธํ„ฐ์—ฌ์•ผ ํ•จ
      • ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
      • ๊ฐ™์€ ํƒ€์ž…๋งŒ ๊ฐ€๋Šฅ (int[] ๊ฐ™์€)
public void DisplayList(params int[] list) {
    foreach (int next in list) {
        Console.WriteLine("Next value {0}", next);
    }
}

Myclass myObject = new Myclass;
int[] myList = new int[6] {2, 4, 6, 8, 10, 12};
myObject.DisplayList(myList);
myObject.DisplayList(2, 4, 1, 17);
  • Parameters (Ruby)
    • Use array formal parameter * (only one in the parameter)
    • ์ค‘๊ฐ„์—๋„ ์˜ฌ ์ˆ˜ ์žˆ์Œ (C#์€ ๋ถˆ๊ฐ€๋Šฅ)
list = [2, 4, 6, 8]

def tester(p1, p2, p3, *p4)
    ...
end

tester('first', mon => 72, tue => 68, wed => 59, *list)
# p1 is 'first'
# p2 is {mon => 72, tue => 68, wed => 59}
# p3 is 2
# p4 is [4, 6, 8]
  • Parameters (Lua)
    • Use ellipsis (...): treated as an array or as a list of values
    • ipairs is an iterator for arrays
    • {...} is an array of the actual parameter values
    • ์ธ์ž ๊ฐœ์ˆ˜ ์ œํ•œ ์—†์Œ
function multiply (...)
    local product = 1
    for i, next in ipairs{...} do
        product = product * next
    end
    return sum
end

print(multiply(2, 3, 4))
function doIt (...)
    local a, b, c = ...
    ...
end

doIt(4, 7, 3)
์–ธ์–ด๋ฌธ๋ฒ•๋ณธ์งˆ
C#params int[]๋ฐฐ์—ด ์ƒ์„ฑ (์ •์ )
Ruby*args๋ฐฐ์—ด๋กœ ์ˆ˜์ง‘ (pack) (๋™์ )
Lua...๊ฐ’ ๋ฆฌ์ŠคํŠธ (not array)
  • Subprograms are collection of statements
    • Procedures: does not return
      • Can change variable (side effect ๋ฐœ์ƒ ๊ฐ€๋Šฅ)
      • Visible in procedure and calling program (ํ˜ธ์ถœํ•œ ์ชฝ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๊ณต์œ ๋˜๋Š” ๋ณ€์ˆ˜์— ์ ‘๊ทผ ๊ฐ€๋Šฅ)
      • Formal parameters that allow the transfer of data to the caller
      • Formal parameter๋Š” ํ•จ์ˆ˜์™€ ํ˜ธ์ถœ์ž ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• 
      • ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š” ์šฉ๋„ ๊ฒฐ๊ณผ๋Š” "๊ฐ’"์ด ์•„๋‹ˆ๋ผ ๋ณ€์ˆ˜ ๋ณ€ํ™”
    • Functions: return value
      • Modeled on mathematics
      • No side effect ideally
      • Can be defined as operator
    • Usually, function can be used as procedures by not defining return

Design issues for subprograms

  • Choice of one or more parameter-passing methods
    • Pass-by-value
    • Pass-by-reference
    • โ€ฆ
  • Type checking
    • Static type checking
    • Dynamic type checking
  • Static or dynamic local variables in subprograms
  • Can be nested
def outer():
    def inner():
        print("nested")
    inner()
  • Can be passed as parameters
    • ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค๋ฅธ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ ๊ฐ€๋Šฅ (first-class function ์ง€์› ์–ธ์–ด)
    • When subprograms are nested and passed, what is the correct referencing environment
    • ํ•จ์ˆ˜ ์•ˆ์—์„œ ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ๊ณณ์— ๋„˜๊ธธ ๋•Œ, ๊ทธ ์™ธ๋ถ€ ํ™˜๊ฒฝ ์ •๋ณด๋„ ํ•จ๊ป˜ ์ „๋‹ฌ
  • Can be overloaded or generic
    • Overloading: ๊ฐ™์€ ์ด๋ฆ„ ๋‹ค๋ฅธ ์‹œ๊ทธ๋‹ˆ์ฒ˜ โ†’ ์ •์  ๋‹คํ˜•์„ฑ
    • Generic: ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐํ™”
  • Closure supported?
    • ํ•จ์ˆ˜์™€ ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋œ ํ™˜๊ฒฝ์˜ ์กฐํ•ฉ

Local referencing environments

  • Local variable

    • Inside subprogram (์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ ์•ˆ์—์„œ ์„ ์–ธ๋œ ๋ณ€์ˆ˜)
    • Static
      • ์„ ์–ธ ์‹œ ๋ฉ”๋ชจ๋ฆฌ์— ๊ณ ์ •๋œ ์œ„์น˜์— ํ• ๋‹น, ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€๋จ
      • [C] keyword static is used for static local variable
      • ํ•จ์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ๋˜๋”๋ผ๋„ ์ด์ „ ๊ฐ’ ์œ ์ง€
    • Stack dynamic (default setting for most languages)
      • ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ์Šคํƒ ํ”„๋ ˆ์ž„์— ์ƒ์„ฑ๋˜๊ณ , ๋ฆฌํ„ด๋˜๋ฉด ์†Œ๋ฉธ
      • [Pro] Flexible, each recursive calls have their own local variable
      • [Pro] If it is in active subprograms, it can be shared
      • [Con] Cost of time for allocation, initialization, deallocation
      • [Con] Must be indirectly accessed (determined only during execution)
      • [Con] Cannot be history sensitive
  • Global variable

    • Defined outside subprogram
    • Can be referenced in the method without declaring
    • If the name of a global variable is assigned in a method
      • Implicitly declared to be a local
      • Does not disturb the global (์„€๋„์ž‰ shadowing ํ˜„์ƒ)
  • Nested subprograms (ํ•œ ํ•จ์ˆ˜ ์•ˆ์— ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ตฌ์กฐ)

    • Create hierarchy of logic and scopes
    • Can be used when it is only needed in another subprogram
    • Want to hide it from others โ†’ ์บก์Аํ™”
    • Allowed in Algol, Pascal, Ada, JavaScript, Python, Ruby and Lua + most Functional languages
    • Not allowed in many descendants of C
def outer():
    def inner():
        print("I'm nested!")
    inner()

Parameter passing methods

  • Semantics models

  • Implementation models

  • Implementing parameter passing methods

  • Parameter passing methods in common languages

  • Type checking parameters

  • Multidimensional arrays as parameters

  • Design considerations

  • Examples

  • Semantics models (formal parameter)

    • in mode: receive data
    • out mode: transmit data
    • inout mode: can do both
    • [EX] list1: in mode, list2: inout mode, list3: out mode
def function(list1, list2):
    list2 = list1 + list2
    list3 = list1 + list2
    return list2, list3
  • Implementation models

    • Pass-by-value
    • Pass-by-result
    • Pass-by-value-result
    • Pass-by-reference
    • Pass-by-name
  • Implementation models

    • Pass-by-value
#include <stdio.h>
void add(int in){
    in = in + 10;
}
void main(){
    int a = 20;
    add(a);
    printf("a: %d", a); // 20
}
  • Actual parameter is used to initialize formal parameter

  • Can implement in-mode (caller โ†’ callee)

  • Implemented by copy (usually)

  • Because the copied value is passed into the function without affecting the original value, it can be used in cases where the original value should not be changed

  • Pro: fast in both linkage cost and access time for scalars

  • Cons

    • Additional storage is required for copy
    • Copy operations and storage can be costly when parameter is large
  • Implementation models

    • Pass-by-result
// Assume pass-by-result
#include <stdio.h>
void add(int in){
    in = 10;
}
void main(){
    int a = 20;
    add(a);
    printf("a: %d", a); // 10
}
  • Implementation for out-mode parameters (callee โ†’ caller)

  • No value is transmitted to the subprogram

  • ์‹ค์ œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐ๊ฐ’์€ ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ , ์˜ค์ง ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ํ›„ ๊ฒฐ๊ณผ๊ฐ’์ด ๋ณต์‚ฌ๋ผ ๋Œ์•„๊ฐ€๋Š” ๊ตฌ์กฐ

  • Its value is transmitted back to the caller's actual parameter

  • Implemented by copy (usually)

  • ํ˜ธ์ถœ ์ „: ์•„๋ฌด ๊ฐ’๋„ ๋ณต์‚ฌ๋˜์ง€ ์•Š์Œ

  • ํ˜ธ์ถœ ํ›„: ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ, ๋‚ด๋ถ€ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์‹ค์ œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์œ„์น˜๋กœ ๋ณต์‚ฌ

  • Ensuring that the initial value of the actual parameter is not used in the called subprogram

  • (+) ๋‚ด๋ถ€ ๋กœ์ปฌ ๋ณ€์ˆ˜๋กœ ์ฒ˜๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ๊ฐ’ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์Œ

  • (-) ์ดˆ๊ธฐ๊ฐ’์„ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ถ€์ ํ•ฉ

  • (-) ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ด๋ฆ„(alias)์ด ๊ฐ™์€ ์‹ค์ œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒฝ์šฐ, ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ (ํŠนํžˆ pass-by-reference์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ)

  • Implementation models

    • Pass-by-result
      • Cons
        • Actual parameter collision
        • 17 or 35 can be assigned to a
        • So, order dependent
[C# ์ฝ”๋“œ]
void Fixer(out int x, out int y) {
    x = 17;
    y = 35;
}
...
f.Fixer(out a, out a);
  • Implementation models
    • Pass-by-result
      • Cons
        • Can choose between two different times to evaluate (time of call or return)
        • ํ‰๊ฐ€ ์‹œ์ (call vs return)์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง โ†’ ์‹ ๋ขฐ์„ฑ์ด ๋–จ์–ด์ง
        • In function DoIt, list[sub] = list[3] or list[5]?
        • Unportable between an implementations: evaluation at beginning and evaluation at the end
public static void DoIt(out int x, out int y)
{
    y = 5;
    x = 17;
}

public static void Main(string[] args)
{
    int sub = 3;
    int[] list = new int[6]{4, 9, 1, 0, 21, 12};
    DoIt(out list[sub], out sub);
    System.Console.WriteLine("{0} {1} {2}", list[3], list[sub], sub);
}
  - Call-time evaluation (ํ˜ธ์ถœ ์‹œ์ ์— ์ฃผ์†Œ ํ‰๊ฐ€): `17 12 5`
    - `// sub[3]` changed to 17, thus the value of x(17) return to `sub[3]`, not `sub[5]`
    - `//โ†’` return address is decided during time of call, not return
  - Return-time evaluation (๋ณต๊ท€ ์‹œ์ ์— ์ฃผ์†Œ ํ‰๊ฐ€):
    - `list[sub]` = `list[3]` โ† sub ๋Š” ์ด๋•Œ 3
    - sub = 5 โ† DoIt() ์—์„œ ๋ณ€๊ฒฝ๋จ
    - โ†’ x = 17 โ†’ `list[3]` = 17
    - sub = 5 ๊ฐ€ ๋จผ์ € ์ ์šฉ๋œ ๋’ค `list[sub]` = `list[5]`
    - โ†’ x = 17 โ†’ `list[5]` = 17
    - โ‡’ ์ฆ‰, `list[sub]`๋Š” `list[3]`์œผ๋กœ ํ‰๊ฐ€๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ.
    - โ†’ ์ฃผ์†Œ๊ฐ€ ํ˜ธ์ถœ ์‹œ์ (call time)์— ํ‰๊ฐ€๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•จ.
  • Implementation models

    • Pass-by-value-result
      • Implementation for inout-mode parameters
      • Pass-by-value + pass-by-result
      • Called by pass-by-copy
  • Implementation models

    • Pass-by-reference
#include <stdio.h>
void add(int &in){
    in = in + 10;
}
void main(){
    int a = 20;
    add(a);
    printf("a: %d", a); // 30
}
  • Implementation for inout-mode parameters
  • Transmits an access path (address)
  • Value of the original variable can be changed
  • Efficient (time and space), no copy
  • Cons
    • Slow to access to formal parameter due to indirect addressing
    • Inadvertent and erroneous changes may be made
    • Aliases can be created โ†’ providing access to nonlocal variables โ†’ reliability problem
void fun(int &first, int &second)
fun(total, total)
// first and second can be aliases
  • Implementation models

    • Pass-by-name
      • Implementation for inout-mode parameters
      • ์ฝ”๋“œ ์กฐ๊ฐ(์ด๋ฆ„)์„ ํ†ต์งธ๋กœ ์ „๋‹ฌํ•ด์„œ, ๊ทธ๋•Œ๊ทธ๋•Œ ์‹คํ–‰ํ•ด๋ณด๋Š” ๋ฐฉ์‹
      • ์‹ค์ œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„ ์ž์ฒด๋ฅผ ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ํ•จ
      • ๋งค๊ฐœ๋ณ€์ˆ˜ ํ‘œํ˜„์‹์ด ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ์žฌํ‰๊ฐ€๋จ (lazy substitution)
      • ์ผ์ข…์˜ ํ…์ŠคํŠธ ์น˜ํ™˜(textual substitution) ๋˜๋Š” ๋งคํฌ๋กœ์ฒ˜๋Ÿผ ๋™์ž‘
      • ๋™์ž‘ ๋ฐฉ์‹
        • Works like pass-by-reference when variable is passed
        • Works like pass-by-value when constant value is passed
        • Complex to implement and inefficient
  • Implementation models

    • Pass-by-name
DoIt(x, y)
    x := x + 1
    y := y + x

DoIt(a[i], i)
์—ฌ๊ธฐ์„œ a[i]๋ž‘ i๋Š” ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋จ (๊ฐ’์ด ์•„๋‹ˆ๋ผ ์ด๋ฆ„์ฒ˜๋Ÿผ)

์‹คํ–‰ ํ๋ฆ„ (pass-by-name):
x := a[i] + 1 โ†’ a[i]๊ฐ€ ๋ณ€๊ฒฝ๋จ
y := i + a[i] โ†’ i ๋ณ€๊ฒฝ๋จ
๋‹ค์‹œ a[i]๋ฅผ ๋ณด๋ฉด ์ด๋ฏธ ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ์ˆ˜ ์žˆ์Œ
โ†’ ํ•œ ์ค„์ด ๋๋‚˜๋ฉด ๋ณ€์ˆ˜ ๊ฐ’์ด ๋‹ฌ๋ผ์ ธ์„œ ๋‹ค์Œ ์ค„ ํ•ด์„์ด ๋ฐ”๋€œ
  • ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ณ , ์‹ค์ˆ˜ํ•˜๊ธฐ ์‰ฝ๊ณ , ์†๋„๋„ ๋А๋ ค์„œ โ†’ ์š”์ฆ˜์€ ๊ฑฐ์˜ ์•ˆ ์”€. Algol 60 ์—์„œ ์‚ฌ์šฉ

  • Implementing parameter passing methods

    • Run-time stack using run-time system takes care for parameter transmission
ํŒŒ๋ผ๋ฏธํ„ฐ์ „๋‹ฌ ๋ฐฉ์‹์„ค๋ช…
wpass-by-value๊ฐ’ ์ž์ฒด๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ „๋‹ฌ๋จ
xpass-by-resultํ•จ์ˆ˜ ์ข…๋ฃŒ ์‹œ ๊ฒฐ๊ณผ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์ „๋‹ฌ
ypass-by-value-resultํ˜ธ์ถœ ์‹œ ๊ฐ’ ์ „๋‹ฌ, ์ข…๋ฃŒ ์‹œ ๊ฒฐ๊ณผ ๋ณต์‚ฌ
zpass-by-reference์ฃผ์†Œ(์ฐธ์กฐ) ์ „๋‹ฌ, ์›๋ณธ ์ง์ ‘ ์ˆ˜์ • ๊ฐ€๋Šฅ
ํŒŒ๋ผ๋ฏธํ„ฐStack ๋™์ž‘ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ
a (w)ํ˜ธ์ถœ ์‹œ w์˜ ๊ฐ’ ๋ณต์‚ฌ โ†’ a ์— ์ €์žฅ์ฝ๊ธฐ ๊ฐ€๋Šฅ, ๋ณ€๊ฒฝํ•ด๋„ w์— ์˜ํ–ฅ ์—†์Œ
b (x)๋ณ„๋„ ์ €์žฅ์†Œ(์Šคํƒ)์— ๊ณต๊ฐ„ ๋งŒ๋“ค๊ณ , ํ•จ์ˆ˜ ์ข…๋ฃŒ ํ›„ b ๊ฐ’์„ x์— ๋ณต์‚ฌํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ b๋Š” ๋กœ์ปฌ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์“ฐ๊ณ , ๋ฆฌํ„ด ์‹œ ๊ฐ’ ๋ณต์‚ฌ
c (y)ํ˜ธ์ถœ ์‹œ y ๊ฐ’ ๋ณต์‚ฌ โ†’ ํ•จ์ˆ˜ ์ข…๋ฃŒ ์‹œ c ๊ฐ’ โ†’ ๋‹ค์‹œ y์— ๋ณต์‚ฌ์–‘๋ฐฉํ–ฅ ๊ฐ’ ๋ณต์‚ฌ (์ง„์ž…, ์ข…๋ฃŒ ์‹œ ๋ชจ๋‘)
d (z)z ์˜ ์ฃผ์†Œ๋ฅผ ์ „๋‹ฌ โ†’ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ์›๋ณธ ์ ‘๊ทผ ๊ฐ€๋Šฅ๋ณ€๊ฒฝ ์‹œ z ๋„ ๋ฐ”๋กœ ๋ฐ”๋€œ
  • Parameter passing methods in common languages
    • [C++] Pass-by-value but pass-by-reference can be achieved by pointer and reference types
void fun(const int &p1, int p2, int &p3) { ... }
  • p1: pass-by-reference but cannot be changed, p2: pass-by-value, p3: pass-by-reference
  • Constant parameter vs in-mode parameter
    • Constant parameter can never be assigned but in-mode parameter can
  • [Java] Pass-by-value but objects are passed by reference
    • No pointer type, scalar cannot be passed by reference
  • [C#] Pass-by-value but pass-by-reference can be achieved by ref
void sumer(ref int oldSum, int newOne) { ... }
...
sumer(ref sum, newValue);
  • Parameter passing methods in common languages
    • [Python, Ruby] Pass-by-assignment
    • All data are object
    • [EX] x = x + 1
      • Takes object referenced by x, increments by 1, then create new object, finally assign new object to x
string = "Hello"
string[0] = 'W' # X
string = "Wello" # O
  • [EX] Scalar cannot be changed in subprogram
  • Reference method of the object is determined depending on the object being passed
    • Mutable Object(list, dict, set) โ†’ Call by reference
    • Immutable Object(str, int, tuple) โ†’ Call by value
# [immutable] call-by-value
def func(x):
    x = x + 1
a = 1
func(a)
# [mutable] call-by-reference
def func(x):
    x.append(5)
a = [1, 2, 3, 4]
func(a)
# [mutable] ??
def func(x):
    x = [1, 2]
a = [1, 2, 3, 4]
func(a)
  • Type checking parameters
    • Most languages require type checking
    • Early programming languages (Fortran 77 and original version of C) did not require
double sin(x)    // avoid type check
double x;
{ ... }

double sin(double x)    // do type check (with coercion), prototype method
{ ... }
  • ํ•จ์ˆ˜ ์„ ์–ธ๊ณผ ํƒ€์ž… ์ •๋ณด๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์—ˆ์Œ
  • In C89, formal parameters can be defined in two ways
  • In C99 and C++, prototype form but avoided by ellipsis
int printf(const char* format_string, ...);
  • Type checking parameters
    • In C#, ref actual parameter needs to be the same with formal parameter
    • In Python, Ruby, objects have types, but variables do not
    • Formal parameters are typeless
    • No type checking of parameter
์–ธ์–ดํƒ€์ž… ๊ฒ€์‚ฌ์„ค๋ช…
C#์—„๊ฒฉํ•œ ํƒ€์ž… ๊ฒ€์‚ฌํ˜•์‹ ๋งค๊ฐœ๋ณ€์ˆ˜(formal parameter)์™€ ์‹ค์ œ ์ธ์ž(actual argument)์˜ ํƒ€์ž…์ด ๋ฐ˜๋“œ์‹œ ์ผ์น˜ํ•ด์•ผ ํ•จ. ref, out ํ‚ค์›Œ๋“œ๋ฅผ ์“ธ ๊ฒฝ์šฐ, ํ˜ธ์ถœ๋ถ€์—๋„ ๋ช…์‹œ์ ์œผ๋กœ ๋ถ™์—ฌ์•ผ ํ•จ โ†’ ํ˜•์‹๊ณผ ํ‚ค์›Œ๋“œ๊นŒ์ง€ ์ผ์น˜ํ•ด์•ผ ์ปดํŒŒ์ผ ํ†ต๊ณผ
C/C++(C89 ์ดํ›„)C89๋ถ€ํ„ฐ ํ•จ์ˆ˜ ํ”„๋กœํ† ํƒ€์ž…์ด ๋„์ž…๋˜๋ฉฐ ํƒ€์ž… ๊ฒ€์‚ฌ ๊ฐ€๋Šฅ. void f(int); f("abc"); โ†’ ์˜ค๋ฅ˜ ๋ฐœ์ƒ. C++์—์„œ๋Š” ๋” ์—„๊ฒฉํ•˜๊ณ  ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ๋„ ์ง€์›
Python๋ณ€์ˆ˜๋Š” ํƒ€์ž… ์—†์Œ๊ฐ์ฒด๋Š” ํƒ€์ž…์„ ๊ฐ€์ง€์ง€๋งŒ, ๋ณ€์ˆ˜ ์ž์ฒด๋Š” ํƒ€์ž…์ด ์—†์Œ. ํ•จ์ˆ˜์˜ ํ˜•์‹ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํƒ€์ž… ์„ ์–ธ์ด ์—†์Œ (๊ธฐ๋ณธ์ ์œผ๋กœ) โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๋„ ํ•˜์ง€ ์•Š์Œ
RubyPython๊ณผ ๋™์ผ๋ณ€์ˆ˜๋Š” ์–ด๋–ค ํƒ€์ž…์˜ ๊ฐ์ฒด๋“  ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ์Œ. ํ•จ์ˆ˜ ์ •์˜ ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ์— ํƒ€์ž…์„ ๋ช…์‹œํ•  ์ˆ˜ ์—†์Œ โ†’ ๋Ÿฐํƒ€์ž„์—์„œ ์ž˜๋ชป๋œ ํƒ€์ž… ์‚ฌ์šฉ ์‹œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ (๋™์  ํƒ€์ž…)
  • Multidimensional arrays as parameters
    • In C and C++, pointer can be used for passing
    • Inclusion of pointer arithmetic
    • Dimension of matrix (row, column) can be passed as parameters
void fun(float *mat_ptr,
         int num_rows,
         int num_cols);
  • Can access element by
    • *(mat_ptr + (row * num_cols) + col) = x;
    • Or macro
#define mat_ptr(r,c) (*mat_ptr + ((r) * (num_cols) + (c)))
mat_ptr(row,col) = x;
  • Multidimensional arrays as parameters
    • In C# and Java, arrays are object
    • Formal parameter for a matrix appear with [][]
    • Use length (Length in C#) to get row and column sizes
float sumer(float mat[][]) {
    float sum = 0.0f;
    for (int row = 0; row < mat.length; row++) {
        for (int col = 0; col < mat[row].length; col++) {
            sum += mat[row][col];
        } //** for (int row ...
    } //** for (int col ...
    return sum;
}
  • Design considerations
    • Efficiency
      • ์‹คํ–‰ ์†๋„์™€ ์ž์› ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•ด ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์ค„์ด๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•จ
      • ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ์— ์ž์ฃผ ์ ‘๊ทผํ•˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„
      • ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›๊ณ , ๋‚ด๋ถ€์—์„œ๋งŒ ์ฒ˜๋ฆฌ
      • ๋ณต์‚ฌ ๋น„์šฉ์ด ํฐ ๊ฐ์ฒด๋Š” ํฌ์ธํ„ฐ๋‚˜ ์ฐธ์กฐ๋กœ ์ „๋‹ฌ (C/C++)
    • Minimize functional side effect
      • ์„œ๋ธŒํ”„๋กœ๊ทธ๋žจ์ด ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋ฐ”๊พธ๋Š” ๊ฒƒ์„ ํ”ผํ•ด์•ผ ํ•จ
      • ์ž…๋ ฅ๊ฐ’๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜(pure function) ์ง€ํ–ฅ
      • ์™ธ๋ถ€ ๋ณ€์ˆ˜(global variables), ์ฐธ์กฐ ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ์€ ๊ฐ€๊ธ‰์  ์“ฐ์ง€ ์•Š๊ธฐ
      • ๋ช…ํ™•ํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜๋กœ ์œ ์ง€
# ๋ถ€์ž‘์šฉ ๋ฐœ์ƒ: ํ•จ์ˆ˜๊ฐ€ ์™ธ๋ถ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ”๊ฟˆ
def add_item_bad(lst):
    lst.append(100)

# ๋ถ€์ž‘์šฉ ์—†์Œ: ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜
def add_item_good(lst):
    return lst + [100]
  • Examples
    • Compare pass-by-value-result and pass-by-reference
void fun (int first, int second) {
    first += first;
    second += second;
}
void main() {
    int list[2] = {1, 3};
    fun(list[0], list[1]);
}
  • Assume that there is no accumulation

  • Pass by value: No changes

  • Pass by reference: list โ†’ {2,6}

  • Pass by value-result: list โ†’ {2,6}

  • Examples

    • Compare pass-by-value-result and pass-by-reference
int i = 3; /* i is a global variable */
void fun(int a, int b) {
    i = b;
}
void main() {
    int list[10];
    list[i] = 5;
    fun(i, list[i]);
}
  • When pass-by-value-result is used, i and a are not alias

    • global variable i is changed within fun
    • But, formal parameter back to caller
  • When pass-by-reference is used, i and a are alias

    • global variable i is changed within fun
    • Formal parameter not back to caller โ†’ i remains 5
  • Examples

void swap(int a, int b) {
    int temp;
    temp = a;
    a = b;
    b = temp;
}
void main() {
    int value = 2, list[5] = {1, 3, 5, 7, 9};
    swap(value, list[0]);  // (1)
    swap(list[0], list[1]); // (2)
    swap(value, list[value]); // (3)
}
  • Assume that there is no accumulation
  • Pass by value: No changes after (1),(2),(3)
  • Pass by reference:
    • (1) value โ†’ 1, list โ†’ {2,3,5,7,9}
    • (2) value โ†’ 2, list โ†’ {3,1,5,7,9}
    • (3) value โ†’ 5, list โ†’ {1,3,2,7,9}
  • Pass by value-result:
    • (1) value โ†’ 1, list โ†’ {2,3,5,7,9}
    • (2) value โ†’ 2, list โ†’ {3,1,5,7,9}
    • (3) value โ†’ 5, list โ†’ {1,3,2,7,9} (when addr is computed at time of call)
      • If addr is computed at time of return
      • value โ†’ 5, list[value==5] โ†’ 2 (out of range error)

Parameter that are subprograms

  • In a certain situation, subprograms needs to be sent as parameters

  • [Issue 1] Type checking function's protocol

    • ์ „๋‹ฌํ•˜๋ ค๋Š” ํ•จ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹(๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐœ์ˆ˜, ํƒ€์ž…, ๋ฐ˜ํ™˜ ํƒ€์ž…)์„ ๊ฐ–๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•จ
    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ ์‹œ ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ํƒ์ง€ํ•˜์ง€ ๋ชปํ•จ
    • โ†’ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์œ„ํ—˜
    • ํ•จ์ˆ˜ ํฌ์ธํ„ฐ(Function Pointer) ํƒ€์ž… ๋ช…์‹œ (C/C++)
      • int compute(int x, int (*func)(int))
      • func๋Š” int(int) ํƒ€์ž… ํ•จ์ˆ˜์—ฌ์•ผ ํ•จ โ†’ ํƒ€์ž… ์ฒดํฌ ๊ฐ€๋Šฅ
  • [Issue 2] Function would be nested โ†’ how to decide referencing environment

    • ํ•จ์ˆ˜๊ฐ€ ์ž์‹ ์„ ๊ฐ์‹ผ ์™ธ๋ถ€ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š”๋ฐ,
    • ๊ทธ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ์ „๋‹ฌ๋˜๋ฉด ์™ธ๋ถ€ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ๋•Œ ์–ด๋–ค ํ™˜๊ฒฝ์„ ๋”ฐ๋ผ์•ผ ํ• ์ง€ ๋ชจํ˜ธํ•จ
    • Shallow binding: environment of the call statement that enacts the passed subprogram (Used for dynamic-scoped languages)
    • Deep binding: environment of the definition of the passed subprogram (Suitable for static-scoped languages)
    • Ad hoc binding: environment of the call statement that passed the subprogram as an actual parameter
    • x is bound to local x in sub1
    • x is bound to local x in sub3
    • x is bound to local x in sub4

Calling subprograms indirectly

  • In a certain situation (event handling in GUI), subprograms must be called indirectly
  • Unknown which subprogram will be called until runtime
  • Done by pointer or reference to subprogram
  • float (*pfun)(float, int);
  • pfun์€ ๋งค๊ฐœ๋ณ€์ˆ˜ (float, int)๋ฅผ ๋ฐ›๊ณ  float์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
#include <stdio.h>
float multiply(float a, int b) {
    return a * b;
}

float divide(float a, int b) {
    return a / b;
}

int main() {
    float (*pfun)(float, int);
    int condition = 1; // ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด
    if (condition)
        pfun = multiply;
    else
        pfun = divide;

    float result = pfun(10.0, 2); // ๊ฐ„์ ‘ ํ˜ธ์ถœ
    printf("Result: %.2f\n", result); // 20.00
    return 0;
}
  • Called by
(*pfun2)(first, second); // ์ „ํ†ต์ ์ธ ํฌ์ธํ„ฐ ๋ฐฉ์‹
pfun2(first, second);   // C์—์„œ ํ—ˆ์šฉ๋˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฌธ๋ฒ•
  • [C#] delegate
    • Reference to method for pass it as parameter
    • delegate๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ์™€ ๋น„์Šทํ•œ ๊ฐœ๋…
    • ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…
    • ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ๋„˜๊ธฐ๊ณ  ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ
public delegate int Change(int x); // ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํƒ€์ž… ์„ ์–ธ,
// int์„ ๋ฐ›์•„ int๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋™์ผํ•œ ํƒ€์ž…์˜ delegate๋ฅผ ๋งŒ๋“ฆ

static int fun1(int x) { return x + 1; }
static int fun2(int x) { return x * 2; } // fun1, fun2๋Š” ๋ชจ๋‘ Change delegate์™€ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๊ฐ™์Œ

Change chgfun1 = new Change(fun1); // fun1์„ ์ฐธ์กฐํ•˜๋Š” delegate ์ƒ์„ฑ
chgfun1 += fun2; // fun2๋„ ์ถ”๊ฐ€ โ†’ ๋ฉ€ํ‹ฐ์บ์ŠคํŠธ delegate
int result = chgfun1(5); // fun1(5), fun2(5) ์ˆœ์œผ๋กœ ์‹คํ–‰๋จ

Overloaded subprograms

  • The same name and referencing environments as another
  • But, unique protocol (number, order types of parameters and return types)
  • Meaning of call is determined by actual parameters
  • [Issue 1] Coercion is allowed?
    • When there is no exact match, should we allow the best match? and how?
  • [Issue 2] The same parameter but different return types
    • How to choose return type?
  • The most common multiple versions of subprogram: constructors
// [C++]
int func(int first, int second) {
    return first + second;
}
float func(float first, float second) {
    return first - second;
}

func(1, 2);      // 3
func(1.0f, 2.0f); // -1.0
func(1.0, 2.0);  // error: call of overloaded 'func(double, double)' is ambiguous
func(1.0, 2.0f); // -1.0, coercion to func(float,float)
func(1.0, 2);    // 3, coercion to func(int,int)
  • ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ํƒ€์ž…์ด ์ตœ์šฐ์„ 
  • ์•”์‹œ์  ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•˜๋ฉด ๊ณ ๋ ค๋จ
  • ๋‘ ๊ฐœ ์ด์ƒ์ด ๋ชจ๋‘ ์•”์‹œ์  ๋ณ€ํ™˜ ๊ฐ€๋Šฅ์ด๋ฉด โ†’ ๋ชจํ˜ธ์„ฑ ์˜ค๋ฅ˜(ambiguous)
// [C++] ambiguous return type
int func(int first, int second) {
    return first + second;
}
float func(int first, int second) {
    return first > second ? first : second;
}
// error: ambiguating new declaration of 'float ...
// [Java]
public static int func(int first, int second) {
    return first + second;
}
public static float func(float first, float second) {
    return first - second;
}

func(1, 2);      // 3
func(1.0f, 2.0f); // -1.0
func(1.0, 2.0);  // no suitable method found for func(double,double), argument mismatch; possible lossy conversion from double to int(float)
func(1.0, 2.0f); // no suitable method โ€ฆ. lossy โ€ฆ
func(1.0, 2);    // no suitable method โ€ฆ. lossy โ€ฆ

// [Java] If not lossy conversion
func('A', 2);    // 67, coercion to func(int, int)
func('A', 2.0f); // 63.0, coercion to func(float,float)
func('A', 'B');  // 131, coercion to func(int,int)

// [Java] ambiguous return type
public static int func(int first, int second) {
    return first + second;
}
public static float func(int first, int second) {
    return (float) (first - second);
}
// error: method func(int,int) is already defined

Generic subprograms

  • Reusability is important for productivity

  • Polymorphism!

    • Ad hoc polymorphism
      • Overloaded subprograms (need not behave similarly each other)
    • Subtype polymorphism
      • OOP, variable of type T can access any object of type T and derived from T
    • Parametric polymorphism
      • Takes generic parameters
      • Parametrically polymorphic subprograms are called generic subprograms
  • Generic functions in C++

  • template function

// Overloaded subprograms
int max(int first, int second) {
    return first > second ? first : second;
}
float max(float first, float second) {
    return first > second ? first : second;
}
double max(double first, double second) {
    return first > second ? first : second;
}

// With template function
template <class Type>
Type max(Type first, Type second) {
    return first > second ? first : second;
}

int x1 = 2, x2 = 3;
max(x1, x2) // dynamically bound to the types
  • Generic functions in C++
  • If overloaded?
template <class Type>
Type max(Type first, Type second) {
    return first > second ? first : second;
}
float max(float first, float second) {
    return first > second ? -first : -second;
}
double max(double first, double second) {
    return first > second ? 2*first : 2*second;
}

max(1, 2)      // 2
max(1.0f, 2.0f) // -2
max(1.0, 2.0)  // 4
// โ†’ specific functions have higher precedence than generic function
  • Generic functions in C++
  • With standard library in std?
#include<iostream>
using namespace std;

template <class Type>
Type max(Type first, Type second) {
    return first > second ? first : second;
}

max(1, 2) // error: call of overloaded 'max(double, double)' is ambiguous
          // โ†’ conflict max() in std
#include<iostream>
using namespace std;

int max(int first, int second) {
    return first > second ? first : second;
}

max(1, 2) // 2
// It's okay to define function for specific type
  • Generic functions in C++
  • template with different types?
template <class Type>
Type max(Type first, Type second) {
    return first > second ? first : second;
}
// max(1, 2.0) // error: no matching function for call to 'max(int, double)
// โ†’ Single type can cover one type only

template <class Type1, class Type2>
Type1 max(Type1 first, Type2 second) {
    return first > second ? first : second;
}
max(1, 2)   // 2
// Need to define different Type
  • Generic functions in C++
  • How about array?
template <class Type1, class Type2>
double max(Type1 first, Type2 second, int index) {
    return first[index] > second ? first[index] : second;
}

int x[3] = {1,2,3};
max(x, 2.0, 2); // 3
// โ†’ array (pointer) can be also covered
  • Generic functions in C++
  • template function vs macro
template <class Type>
Type max(Type first, Type second) {
    return first > second ? first : second;
}

#define max(a, b) ((a) > (b)) ? (a) : (b)
  • Macro can be used but problem when there is side effect
max(x++, y)
โ†’ ((x++) > (y) ? (x++) : (y))
// x is increased twice

Design issues for functions

  • Side effect allowed?
    • To prevent it, enforce im-mode parameters
    • [Imperative] have side effects
    • [Functional] have no variable, so no side effects
  • What type can be returned?
    • Mostly (Python, Ruby, and Lua), any type can be returned, passed as parameters
    • [C] Arrays and functions are handled by pointer
    • [Java, C#] Method (class function) is used, any type and class can be returned
  • How many values can be returned
    • Ruby, Lua, Python can return multiple values
    • a, b, c = fun()
    • Tuple is used

User-defined overloaded operators

  • Operator can be also overloaded
  • [C++] Several operators can be overloaded
    • Exceptions: ., .*, ::, ?:
    • Define operator as a method in class
class Complex
{
public:
    Complex(int real, int img){
        this->real = real;
        this->img = img;
    }
    Complex operator+(const Complex& right){
        int real = this->real + right.real;
        int img = this->img + right.img;
        return Complex(real, img);
    }
private:
    int real;
    int img;
};

Complex x1 = Complex(1,1);
Complex x2 = Complex(2,2);
Complex x3 = x1 + x2;
  • Operator can be also overloaded
  • [Python] For addition for complex numbers
    • Define addition operation in special method(__add__)
def __add__ (self, second):
    return Complex(self.real + second.real, self.imag + second.imag)

Closures

  • Function is also object
  • Can be pass to other function, returned by function and stored in data structure
# Function can be passed
def funcO(func):
    return func()

def funcI():
    return "function inside"

print(funcO(funcI))
# Function can be stored in list
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    return a / b

func_lst = [add, subtract, multiply, divide]
n = 1
m = 2
for func in func_lst:
    print(func.__name__, ":", func(n, m))

# add : 3
# subtract : -1
# multiply : 2
# divide : 0.5
  • Function can be nested
  • inner() can only be called inside outer()
def outer():
    print("Here is outer region.")
    def inner():
        print("Here is inner region.")
    inner()

outer()
  • A closure is a function returned by a function
def addNumber(fixedNum):
    def add(number):
        return fixedNum + number
    return add

func = addNumber(10)
func(20) # 30
func(30) # 40
  • Each of these calls returns a different version of the closure because they are bound to different values of fixedNum
  • lifetime of the version of fixedNum created when addNumber is called must extend over the lifetime of the program
  • This subprogram can be called in other place
  • โ†’ Subprogram needs to remembers the referencing environment in which it was defined
  • Benefits
    • Global variables can be reduced.
    • Similar types of code can increase the reuse rate
def addNumber(fixedNum):
    def add(number):
        return fixedNum + number
    return add

func1 = addNumber(10)
func2 = addNumber(20)

print(dir(func1))
print(func1.__closure__[0].cell_contents)
print(func2.__closure__[0].cell_contents)
['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__',
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__',
'__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__type_params__']
(<cell at 0x7fb35f401240: int object at 0x564e4ecb58c8>,)
10
20
  • Since function is also an object, we can check its properties through the dir() function, and we can see that there is __closure__ in the checked properties.

  • __closure__ is tuple

  • We can check information of closure

  • A closure can model high-level module such as neural network

def nonlinear_activation():
    e = 15
    def thre(x):
        return 1 if x > e else 0
    return thre

def linear_model():
    a = 3
    b = 5
    def mul_add(x):
        return a * x + b
    return mul_add

lm = linear_model()
print(lm(1), lm(2), lm(3), lm(4), lm(5))
na = nonlinear_activation()
print(na(lm(1)), na(lm(2)), na(lm(3)), na(lm(4)), na(lm(5)))

# 8 11 14 17 20
# 0 0 0 1 1
  • Neural network consists of huge amount of linear model + nonlinear activation

  • Each model has similar structure (process) with only different learnable parameters

  • A closure with lambda

def linear_model():
    a = 3
    b = 5
    return lambda x: a * x + b

lm = linear_model()
print(lm(1), lm(2), lm(3), lm(4), lm(5))
# 8 11 14 17 20
  • Change local variable of closure
def linear_model():
    a = 3
    b = 5
    sum = 0
    def mul_add(x):
        nonlocal sum
        result = a * x + b
        sum += result
        print("sum:%d" % sum)
        return result
    return mul_add

lm = linear_model()
print(lm(1), lm(2), lm(3), lm(4), lm(5))

# sum:8
# sum:19
# sum:33
# sum:50
# sum:70
# 8 11 14 17 20

Coroutines

  • Special subprogram

  • In coroutine, caller and called coroutines are more equitable

  • In common subprogram, caller and callee have master-slave relationship

  • Coroutines can have multiple entry points

  • Controlled by symmetric unit control model.

  • Resume: secondary executions of a coroutine often begin at points other than its beginning

  • History sensitive

  • co1() โ†’ co2(2) โ†’ co1() โ†’ co3() โ†’ co1()

  • Only one coroutine is actually in execution at a given time โ†’ quasi-concurrency

  • Related to the way multiprogramming operating systems

  • Usually, master unit handle. EX. card game simulation

  • (a) execution of coroutine A is started by the master unit

  • (b) execution of coroutine B is started by the master unit

  • Coroutine execution sequence with loops

def coroutine1():
    print('callee 1')
    x = yield 1
    print('callee 2: %d' % x)
    x = yield 2
    print('callee 3: %d' % x)

task = coroutine1()
i = next(task)    # print callee 1, i = 1
i = task.send(10) # print callee 2:10, i = 2
task.send(20)     # print callee 3: 20, then StopIteration exception

# callee 1
# callee 2: 10
# callee 3: 20
# StopIteration
์ตœ๊ทผ ์ˆ˜์ •: 26. 6. 12. ์˜คํ›„ 3:28
Contributors: kmbzn, Claude Sonnet 4.6
Prev
8.0. Statement Level Control Structures
Next
9. Implementing Subprogram

BUILT WITH

CloudflareNode.jsGitHubGitVue.jsJavaScriptVSCodenpm

All trademarks and logos are property of their respective owners.
ยฉ 2026 kmbzn ยท MIT License