[PL] 06. Expressions and Assignment Statements
Expression
프로그래밍 언어에서 computation을 특정하는 기본 수단
V : (State, Expr) -> Value
V는 상태 S에서의 E의 값
S = {x=1, y=2} , V(S, x+y) = 3
- 산술 계산 Arithmetic Expression : V(s, E1+E2) = V(s, E1) + V(s, E2)
- 비교 연산 Relational Expression = 논리 연산 Boolean : V(s, E1==E2) = T if V(s, E1) == V(s, E2)
- Logic Expression
Arithmetic Expression
초기 프로그래밍 언어 개발의 동기
구성
- operator(연산자)
- operand(피연산자)
- 괄호
- function call(함수 호출)
Operator : 단항 연산자, 이항 연산자, 삼항 연산자 (각각 1, 2, 3개의 피연산자를 가짐)
Design Issues
- 연산자 우선순위
- 연산자 결합성
- 피연산자의 평가 순서
- 연산자의 피연산자로 function call이 쓰였을 때, 그 function으로 인한 side effect는 어떻게 처리할 것인지
- 연산자 overloading을 허용할 것인지 (C/Java는 허용 X , C++/Python은 허용)
- 하나의 수식에 여러 Type을 가진 변수들이 섞여 있으면 어떻게 처리할 것인지 (Type mixing)
일반적인 연산자 우선순위 (Operator Precedence Rules)
서로 다른 우선순위 수준을 가진 "인접한" 연산자의 평가 순서를 정의
- 괄호
- 단항 연산자
- 지수(**)
- * /
- + -
- (그 뒤: 비교 -> 논리(&&, ||) -> 조건(?, :) -> 대입)
연산자 결합성 (Operator Associativity Rule)
동일한 우선순위를 갖는 연산자가 두 개 이상 인접한 경우, 무엇을 먼저 수행하느냐에 대한 규칙
- Left to Right (left associative) (대부분의 이항 연산자)
- Right to Left (right associative) (대부분의 단항 연산자와 대입 연산자, 그리고 지수 연산자(**))
APL의 초기 버전 : 모든 operator의 우선순위 같고 결합은 ‘Right to Left’로 수행함
Operand Evaluation Order (피연산자 평가 순서)
- Variables 변수 : 메모리에서 값을 가져온다.
- Constants 상수 : 메모리에서 가져오거나, 코드 자체에 들어가 있을 수 있음. 코드가 내재하고 있다.
- 괄호 : 먼저 계산한다.
- function call이 operand로 쓰였을 때 그로 인한 영향을 연산자 계산 이전에 반영? 혹은 이후에 반영?
function call이 Expression의 변수의 값을 안 바꾸면 상관 X, 바뀌는 경우 => Global 변수, 2-way parameter
Function Side Effects의 2가지 해결법
- function call에 의해서 피연산자의 값이 안 바뀌도록 -> Global 변수, 2-way parameter 을 못쓰게 한다. function에서 parameter change와 non-local reference가 없게 => 프로그램의 flexibility가 떨어진다.
- function call에 의해서 바뀌는 값의 순서를 명확하게 지정 => compiler optimization(최적화)이 제한된다.
Referential Transparency를 보장한다.
-> 같은 함수에 같은 파라미터가 들어가면 같은 리턴값이 나오게 한다.
같지 않게 만드는 경우
- Global 변수
- 2-way parameter
- Local 변수이지만 Static일 때
Referential Transparency의 장점 : Readability 높아짐, 프로그램의 Semantic(의미)를 이해하기 쉽다. (참조 투명성)
완벽한 Referential Transparency를 보장하는 언어는 functional language (변수를 안 쓰는 언어, 모든 값은 상수)
Overloaded Operators
잘 사용하면 Readability를 높이지만 오히려 헷갈리게 만들 수도 있다.
Python, C++은 User defined operator overload를 지원한다. C, Java는 지원 X (Java의 String ‘+’는 예외 사항)
Type Conversions
- 명시적인 타입 변환 Type Casting (개발자가 명시적으로 표기하는 것이므로 거의 모든 프로그래밍 언어는 지원)
- 암묵적인 타입 변환 Coercion (장점 : Flexibility 상승, 단점 : Reliability 하락) (Imperative 프로그래밍 언어에서는 지원) (Functional 프로그래밍 언어는 허용 X) (-> 작은 것에서 큰 것으로 갈 때(widening conversion)는 해준다. 반대는 X)
- Narrowing conversion = float to int (큰 것에서 작은 것으로 좁힘)
- Widening conversion = int to float (대부분 문제가 안 됨) (작은 것에서 큰 것으로 넓힘)
Mixed Mode (Coercion이 되어야 가능 = Functional 프로그래밍 언어는 명시적으로 변환해줘야 사용 가능)
Errors in Expressions : 수학적 문제 (zero-division) / 컴퓨터의 한계 (overflow) -> Error는 run-time system에 의해 자주 무시됨
비교 연산 Relational Expression / 논리 연산 Boolean Expression
Relational Expression
- Relational Operator와 다양한 타입의 피연산자를 사용
- Boolean 형태로 평가
- JavaScript와 PHP에는 ‘===’와 ‘!==’라는 두 가지 추가적인 관계 연산자가 존재
- 이 연산자들은 ‘==’와 ‘!=’와 유사하지만, 피연산자를 강제 coercion하지 않는다.
- Ruby는 ‘==’를 coercion하는 등호 관계 연산자로 사용, coercion이 필요하지 않은 경우에는 ‘eql?’을 사용
Boolean Expression
피연산자가 Boolean이고 결과도 Boolean이다.
C에서 a<b<c는 a<b의 결과가 0 또는 1로 나오고 그 값이 c와 비교되므로 원하는 대로 계산이 되지 않는다.
Short Circuit Evaluation
(Expr1) && (Expr2) 에서 Expr1이 False이면 Expr2는 평가를 하지 않고 그냥 0을 리턴
4가지 언어 모두 Short Circuit Evaluation을 지원함
(&&, ||) / 비트 연산자 &와 |는 Short Circuit을 사용하지 않음
( a < b ) || ( b++ / 3) => 앞 expression의 참/거짓 여부에 따라 side effects가 발생할 수 있음
Assignment Statements
<target_var> <assign_operator> <expression>
assign_operator는 Fortran, BASIC, C기반 언어는 ‘=’ / Ada는 ‘:=’
Compound Assignment Operator
+= 등. ( a = a + b => a += b)
Unary Assignment Operator (단항 연산자)
++. --
sum = ++count : count 증가 후 대입
sum = count++ : 대입 후 count 증가
count++ : count 증가
-count++ : count 증가 후 부정 (int count = 5; int result = -count++; result는 -6, count는 6)
Assignment statement의 결과는 Expression으로 Operand로 쓰일 수 있다. ex) (ch = getchar()) != EOF
단점 : Expression side effect를 발생시킬 수 있다.
Multiple Assignments
Perl, Ruby, Lua 등, (&first, &second, &third) = (20, 30, 40); / (&first, &second) = (&second, &first);
C/C++은 같은 값을 다른 변수에는 넣을 수 있음.
Python은 다른 값을 다른 변수에도 넣을 수 있음. Java는 안 됨
Mixed Mode Assignment
4가지 언어 다 coercion을 지원하므로 지원함