'Scala'에 해당되는 글 5건

  1. 2011.08.19 Kotlin
  2. 2009.11.22 Scala 주의사항
  3. 2009.10.18 Scala의 Option
  4. 2009.09.23 Scala로 Eclipse plugin 개발하기
  5. 2009.08.22 Scala에서의 리스트 1

Kotlin

프로그래밍 2011. 8. 19. 20:18

Jetbrains 에서 만들고 있는 JVM 기반의 언어이다.
만든 이유가 재미있는데, Scala를 개발하는데 써먹어보려고 했으나 언어가 너무 복잡하여 Kotlin 을 만들었다고 한다. 그래서인지 공식 홈페이지에 Scala와 비교해놓은 페이지도 있다.
과연 복잡해지지 않고 버틸 수 있을까? (언어가 범용성을 가지려면 어느 정도 복잡해지는 것은 피할 수 없다.)
Scala를 어떻게든 개선해보는게 더 낫지 않을까?

언어에 대한 좀 더 상세한 내용은 여기에서 볼 수 있다.

링크한 페이지에 댓글 중에 재미있는 문답이 있는데,

우왕굳~~

Posted by lispholic
,

Scala 주의사항

Scala 2009. 11. 22. 21:37

클래스 객체 사용하기

Java 에서는 클래스 객체를 쓰려면 String.class 같은 식으로 쓴다. Scala는 이 문법을 쓰지 않고 아래처럼 한다.

val cls = classOf[String] ;

타입명을 []안에 쓰게하여 언어의 다른 요소와 일관성을 맞추려 한 것 같다. 하지만 개인적으로는 Java문법이 더 편하다.

캐스팅하기, 특정 타입인지 검사하기

Java에서는 캐스팅할 때 C와 같은 문법을 쓰는데 Scala는 아래처럼 한다.

// 특정 객체를 String 타입으로 캐스팅
val str = someObj.asInstanceOf[String];

캐스팅 문법은 Scala가 더 좋다.

객체가 특정 타입인지 검사할 때 Java는 instanceof연산자를 쓴다.

if( someObj instanceof Integer ) {
    Integer i = (Integer)someObj ;
    System.out.println(i*i) ;
}
else {
    // Integer가 아닌 경우 처리
}

Scala에는 instanceof에 해당하는게 없고 패턴매칭을 쓴다.

someObj match {
    case i:Int => println (i*i)
    case _ => // Int가 아닌 경우 처리
}

이것 역시 Scala가 더 낫다.

Annotation

아래의 Java 어노테이션을 Scala에서 쓴다고 해보자.

package test;
import java.lang.annotation.*;
@Target({ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConsAnnotation {
}

이 어노테이션을 아래 class의 생성자에 붙이려면 아래처럼 하면 될 것 같다.

package test
@ConsAnnotation
class TargetClass1 (num:Int){
}

컴파일해보면 잘 된다. 하지만 아래코드를 실행해보면

package test
object Run1 {
    def main(args:Array[String]) {
        val cls = classOf[TargetClass1] ;
        println(cls + " ==> " + cls.getAnnotation(classOf[ConsAnnotation])) ;
        cls.getConstructors().foreach{ cons =>
            println(cons + " ==> " + cons.getAnnotation(classOf[ConsAnnotation])) ;
        }
    }
}

뭔가 문제가 있음을 알 수 있다.

        class test.TargetClass1 ==> @test.ConsAnnotation()
        public test.TargetClass1(int) ==> null
        

이렇게 하면 생성자가 아니라 클래스에 어노테이션이 붙는다. 생성자에 붙이려면 아래처럼 클래스명과 매개변수 리스트 사이에 어노테이션을 넣어야 한다. 그리고 어노테이션에 매개변수를 넣지 않더라도 ()를 꼭 붙여야 한다.(안 붙이면 컴파일 오류가 난다.)

package test
class TargetClass2 @ConsAnnotation()(num:Int ){
}
        class test.TargetClass2 ==> null
        public test.TargetClass2(int) ==> @test.ConsAnnotation()
        

이 어노테이션은 생성자에만 붙도록 되어있음에도 클래스에 붙일 수 있다는 것은 뭔가 이상하다. 내가 확인해본 바로는 scalac는 어노테이션의 Target설정을 확인하지 않는다고 한다.

Posted by lispholic
,

Scala의 Option

Scala 2009. 10. 18. 21:26

Scala에는 Option이라는게 있는데 이것을 이용하면 귀찮은 코드를 줄일 수 있다. 예를 들어 java 에서는 뭔가를 리턴해야하는데 그럴 수 없는 경우 보통 null을 리턴한다. 그러면 받는 쪽에서는 받은게 null이 아닌지 항상 확인해야 한다.

    SomeObject obj = callSomeMethod() ;
    if (obj == null) {
        // 받은게 없는 경우 동작
    }
    else {
        // 정상 객체를 받은 경우 동작
    }

이런 귀찮은 것을 처리하기 위해 Null Object Pattern 을 쓰기도 한다. 즉 null을 리턴하는 대신에 아무 것도 아닌 객체를 리턴하는 것이다. Effective Java에는 배열이나 컬렉션을 리턴해야 할 때 리턴할게 없으면 null을 리턴하지 말고 빈 배열을 리턴하라는 내용이 나오는데 이것도 같은 것이다.

Scala의 OptionNull Object Pattern을 일반화시켜 쓰기 쉽게 해 놓은 것이다. 어떤 메소드의 리턴 타입이 Option인 경우 리턴할 객체를 Some으로 감싸서 리턴하거나 리턴할 게 없으면 None을 리턴하면 된다.

    def func(a : Int) : Option[String] = {
         if (a > 0) Some(a.toString) else None
    }

Option은 컬렉션 인터페이스를 구현했기 때문에 map() 메소드를 이용하여 필요한 필요한 동작을 수행하면 된다. Some을 받았다면 감싸고 있는 객체에 대해 뭔가 동작을 하게 되고, None을 받은 경우에는 아무 것도 하지 않게 된다. 이렇게 함으로써 받는쪽에서 null검사를 할 필요가 없어진다.

    val b = func(0) ;
    b.map{print _} ; // 출력 없음
    val c = func(1) ;
    c.map{print _} ; // 1 출력

다만 이것에 단점도 있는데, 뭔가를 리턴할 때는 객체를 하나 더 만들게 된다는 것이다. 그리고 리턴받은게 없은 경우 뭔가를 해야한다면 결국 null 검사 비슷한 것을 해야한다.

Posted by lispholic
,

Scala 로 Eclipse 플러그인을 개발하는 것에 대해 간략히 기록해본다.

  1. eclipse scala plugin 을 설치해야 한다. 여기의 내용을 참고하여 설치한다.
  2. 다음으로 플러그인 프로젝트(Scala 프로젝트가 아니다)로 새 프로젝트를 하나 만든다.
  3. 프로젝트에서 마우스 우클릭 Scala -> Add Scala Nature 를 선택하여 Scala 관련 기능을 쓸 수 있게 한다.
  4. 플러그인 설정 편집창의 dependency 탭에서 scala.library를 추가한다.

이렇게 한다음 Scala 로 org.eclipse.jface.viewers.IStructuredContentProvider 구현체를 만들어 사용해보았다.

package scala_test
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
class ScalaContentProvider extends IStructuredContentProvider {
    def inputChanged(v : Viewer , oldInput: Object, newInput:Object) : Unit = {
    }
    def dispose() {
    }
    def getElements(parent:Object):Array[Object] = {
        val x : Array[Object] = Array( "Scala 1", "Scala 2", "Scala 3" );
        return x ;
    }
}

그리고 다음처럼 이 클래스를 java로 되어있는 쪽에서 가져다 쓴다.

    public void createPartControl(Composite parent) {
        this.viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
                | SWT.V_SCROLL);
        
        ScalaContentProvider c = new ScalaContentProvider();
        for(Class i : ScalaContentProvider.class.getInterfaces()) {
            System.out.println(i.getName()) ;
        }
        this.viewer.setContentProvider(c);
        this.viewer.setLabelProvider(new ViewLabelProvider());
        this.viewer.setInput(getViewSite());
    }

실행시켜보면 잘 된다.

그런데 아직 플러그인에 문제가 있는 것인지 ScalaContentProvider를 가져다 쓰는 쪽에 오류마크가 뜬다. (실행에는 문제가 없다.) 아래 화면처럼 ScalaContentProviderorg.eclipse.jface.viewers.IStructuredContentProvider를 구현하는데도 이런 마크가 표시된다. 아직은 Scala를 eclipse 플러그인 개발하는데 쓰기는 쉽지 않은 듯 하다.


일단 임시 해결책이 있는데, org.eclipse.jface.viewers.IStructuredContentProvider로 캐스팅을 하는 것이다. 좀 마음에 안들기는 하지만 일단 에러 표시는 사라진다.

        this.viewer.setContentProvider((IStructuredContentProvider)c) ;
Posted by lispholic
,

Scala에서의 리스트

Scala 2009. 8. 22. 17:52

Scala 는 기본적으로 Lisp과 유사하게 head - tail 스타일의 LinkedList 를 사용한다. 그런데 Scala의 immutable주의와 리스트가 혼합되면서 약간 특이한 구조가 되었다.

일반적으로 대부분의 언어에서는 리스트와 유사한 자료구조는 뒤에 데이터를 넣는 것이 효율적이다 (C++의 vector , java의 ArrayList , python 의 리스트 등). 그리고 다른 자료구조 (C++ 의 deque 등)도 뒤에 넣는 것이 앞에 넣는 것에 비해 특별히 비효율적이지는 않기 때문에 대부분 아무생각없이 뒤에 넣는 방식을 쓴다. 그리고 뒤에 넣으면 나중에 넣은게 뒤에 있게 되므로 좀 더 자연스럽다.

그런데 Scala의 기본 List 는 정반대이다. List 를 immutable 로 만들기 위해 리스트에 데이터를 넣을 때 원래의 리스트를 수정하지 않기로 결정했고, 그래서 새로 만든 노드를 원래 리스트의 앞에 붙인다. (head - tail 구조인 리스트에서 원래의 리스트를 수정하지 않고 뒤에 자료를 추가하는 방법은 없다.)

그래서 리스트를 붙이는 연산자인::는 약간 특이하게 동작하는데 오른쪽 매개변수에 대해 메소드를 호출하는 식으로 동작한다. 즉

        "abc" :: Nil

위의 코드는 실제로는 아래처럼 동작하고, 새로 만든 노드를 리턴한다.

        Nil.::("abc")

이해는 하겠는데 뭔가 사파스럽다.

Posted by lispholic
,