Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 243. Scala 개발 환경 구성(JVM, 닷넷) [링크 복사], [링크+제목 복사]
조회: 17046
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

Scala 개발 환경 구성(JVM, 닷넷)

JVM 환경의 차세대 언어로 떠오르고 있는 Scala 언어가 눈길을 끄는군요. (주의할 것은 Scalar가 아니라 ^^ Scalability의 Scala입니다.) C# 개발자로써 자바의 답답한 구문에 숨이 막힐 것 같다면 스칼라 언어가 답이 될 수 있겠습니다. 그나저나 생각보다 역사가 꽤 깊은데요. 2003년에 나와서 10년이 넘었기 때문에 나름 꽤 안정적인 기반을 구축한 것 같습니다.

Scala
; http://www.scala-lang.org/

다운로드는 위의 사이트에서 현재 2.11.2 버전을 받을 수 있습니다. 윈도우 환경의 경우 MSI 설치 파일이 제공되며 실행 후에는 "c:\Program Files (x86)\scala\bin" 폴더에 바이너리가 생성되고 해당 경로가 PATH 환경 변수에 등록됩니다. 그래서 cmd.exe 창만 띄운 후 scala라고 입력하면 REPL 환경이 실행됩니다.

E:\>scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala>

아쉽게도 현재 윈도우 환경의 REPL에서는 화살표 키가 먹지 않아서,

Use arrow keys in scala REPL gives Chinese character
; https://issues.scala-lang.org/browse/SI-8535

이전 입력어를 다시 재사용하려면 Ctrl+P 키를 눌러 우회해야 합니다. (여기서... 10년의 안정화 기간이라는 것은 단지 언어에 국한되었음을 인지하게 됩니다. ^^;) 그 외에 단축키 및 내부 명령어는 다음과 같습니다.

Ctrl+L: 도스의 cls와 같은 역할
:q (또는 :quit): REPL 종료

하지만 곧 cmd.exe를 뒤로 하고 역시 통합 개발환경이 필요하다는 생각이 절실하게 듭니다. ^^

Scala IDE - Version 3.0.3
; http://scala-ide.org/

위의 링크에 가서 "Download IDE" 이미지 버튼을 누르면 오늘자 기준으로 2.11.2 버전의 스칼라가 통합된 이클립스를 받을 수 있고, 압축을 풀어 실행한 후 "File" / "New" / "Scala Project" 메뉴를 선택해 새로운 스칼라 프로젝트를 생성할 수 있습니다.

scala_ide_1.png

그다음 "File" / "New" / "Scala Application" 메뉴를 선택해 새로운 스칼라 소스 코드 파일 "Main.scala"로 추가한 다음 아래와 같이 간단하게 코딩을 해주고,

object Main extends App {
 override def main(args: Array[String]) {
    println("Hello, World!")
  }
}

Ctrl+F11 키를 눌러주면 실행이 되어 콘솔 창에 "Hello, World!" 문자열이 출력됩니다.

또한 "Window" / "Show View" / "Scala Interpreter" 메뉴를 선택하면 이클립스에 로드된 프로젝트를 문맥으로 어느 정도의 기능을 갖춘 REPL 창이 뜹니다.




스칼라 언어는 닷넷 용도 지원하고 있는데요. 제법 양호한 것처럼 들리지만,

Scala comes to .Net
; http://www.scala-lang.org/old/node/10299.html

구현은 아직 미미합니다. 아래의 사이트에서 공개적으로 진행되고 있는데,

magarciaEPFL/scaladotnet 
; https://github.com/magarciaEPFL/scaladotnet

"Scala comes to .Net" 글에서는 금방 될 것처럼 이야기하고 Visual Studio용 플러그인도 내놓는다고 했지만 마지막 커밋 기록이 3년이 넘은 걸로 봐서 그다지 신뢰할 수 있는 수준은 아닌 것 같습니다.

어쨌든 일단 2012년 3월 10일 릴리즈된 버전으로 다운로드 받고,

scaladotnet - Download Packages
; https://github.com/magarciaEPFL/scaladotnet/downloads

실행해봤으나, 처음부터 예외가 발생하는 군요. ^^;

E:\scala>scalacompiler.exe

Unhandled Exception: System.TypeInitializationException: The type initializer for 'scala.tools.nsc.Main$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.tools.nsc.Properties$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.Predef$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.package$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.collection.Traversable$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.util.control.NoStackTrace$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.runtime.ScalaRunTime$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.compat.Platform$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'scala.util.Properties$' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'java.nio.charset.StandardCharsets' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'java.lang.StdIO' threw an exception. 
---> java.lang.NullPointerException: charset is null
   at java.security.AccessController.doPrivileged(Object , AccessControlContext, CallerID )
   at java.security.AccessController.doPrivileged(PrivilegedAction action, CallerID )
   at java.nio.charset.Charset.lookupViaProviders(String )
   at java.nio.charset.Charset.lookup2(String )
   at java.nio.charset.Charset.lookup(String )
   at java.nio.charset.Charset.defaultCharset()
   at sun.nio.cs.StreamEncoder.forOutputStreamWriter(OutputStream out, Object lock, String charsetName)
   at java.io.OutputStreamWriter..ctor(OutputStream out)
   at java.io.PrintStream..ctor(Boolean , OutputStream )
   at java.io.PrintStream..ctor(OutputStream out, Boolean autoFlush)
   at java.lang.StdIO..cctor()
   --- End of inner exception stack trace ---
   at java.lang.System.get_out()
   at java.lang.Class$3.run()
   at java.lang.Class$3.run()
   at java.security.AccessController.doPrivileged(Object , AccessControlContext, CallerID )
   at java.security.AccessController.doPrivileged(PrivilegedAction action, CallerID )
   at java.lang.Class.checkInitted()
   at java.lang.Class.privateGetDeclaredConstructors(Boolean )
   at java.lang.Class.getConstructor0(Class[] , Int32 )
   at java.lang.Class.newInstance0(CallerID )
   at java.lang.Class.newInstance(CallerID )
   at sun.nio.cs.FastCharsetProvider.lookup(String )
   at sun.nio.cs.FastCharsetProvider.charsetForName(String charsetName)
   at java.nio.charset.Charset.lookup2(String )
   at java.nio.charset.Charset.lookup(String )
   at java.nio.charset.Charset.forName(String charsetName)
   at java.nio.charset.StandardCharsets..cctor()
   --- End of inner exception stack trace ---
   at scala.util.Properties$.scalaProps()
   at scala.util.PropertiesTrait$class.scalaPropOrNone(PropertiesTrait $this, String name)
   at scala.util.Properties$.scalaPropOrNone(String name)
   at scala.util.PropertiesTrait$class.$init$(PropertiesTrait $this)
   at scala.util.Properties$..ctor()
   at scala.util.Properties$..cctor()
   --- End of inner exception stack trace ---
   at scala.compat.Platform$..ctor()
   at scala.compat.Platform$..cctor()
   --- End of inner exception stack trace ---
   at scala.Array$.copy(Object src, Int32 srcPos, Object dest, Int32 destPos, Int32 length)
   at scala.collection.immutable.HashSet$.HashTrieSet.updated0(Object key, Int32 hash, Int32 level)
   at scala.collection.immutable.HashSet$.HashSet1.updated0(Object key, Int32 hash, Int32 level)
   at scala.collection.immutable.HashSet.$plus(Object e)
   at scala.collection.immutable.HashSet.$plus(Object elem1, Object elem2, Seq elems)
   at scala.collection.immutable.Set$.Set4.$plus(Object elem)
   at scala.collection.immutable.Set$.Set4.$plus(Object elem)
   at scala.collection.SetLike.$anonfun$$plus$plus$1.apply(Object v1, Object v2)
   at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized $this, Object z, Function2 f)
   at scala.collection.immutable.List.foldLeft(Object z, Function2 f)
   at scala.collection.AbstractTraversable.$div$colon(Object z, Function2 op)
   at scala.collection.SetLike$class.$plus$plus(SetLike $this, GenTraversableOnce elems)
   at scala.collection.AbstractSet.$plus$plus(GenTraversableOnce elems)
   at scala.collection.TraversableOnce$class.toSet(TraversableOnce $this)
   at scala.collection.AbstractTraversable.toSet()
   at scala.runtime.ScalaRunTime$..ctor()
   at scala.runtime.ScalaRunTime$..cctor()
   --- End of inner exception stack trace ---
   at scala.sys.SystemProperties$.noTraceSupression()
   at scala.util.control.NoStackTrace$..ctor()
   at scala.util.control.NoStackTrace$..cctor()
   --- End of inner exception stack trace ---
   at scala.util.control.NoStackTrace$class.fillInStackTrace(NoStackTrace $this)
   at scala.util.control.BreakControl.fillInStackTrace()
   at java.lang.Throwable.instancehelper_fillInStackTrace(Exception this)
   at java.lang.Throwable..ctor()
   at scala.collection.Traversable$..ctor()
   at scala.collection.Traversable$..cctor()
   --- End of inner exception stack trace ---
   at scala.package$..ctor()
   at scala.package$..cctor()
   --- End of inner exception stack trace ---
   at scala.Predef$..ctor()
   at scala.Predef$..cctor()
   --- End of inner exception stack trace ---
   at scala.tools.nsc.Properties$.scalaProps()
   at scala.util.PropertiesTrait$class.scalaPropOrNone(PropertiesTrait $this, String name)
   at scala.tools.nsc.Properties$.scalaPropOrNone(String name)
   at scala.util.PropertiesTrait$class.$init$(PropertiesTrait $this)
   at scala.tools.nsc.Properties$..ctor()
   at scala.tools.nsc.Properties$..cctor()
   --- End of inner exception stack trace ---
   at scala.tools.nsc.Driver..ctor()
   at scala.tools.nsc.Main$..ctor()
   at scala.tools.nsc.Main$..cctor()
   --- End of inner exception stack trace ---
   at Main(String[] args)

관련 이슈가 있지만 답이 없는 상황.

scalacompiler.exe NullPointerException #3 
; https://github.com/magarciaEPFL/scaladotnet/issues/3

알고 보니, 현재 닷넷용 프로젝트는 중단된 상황이라고 합니다.

what is the status of scala for .net ? 
; https://groups.google.com/forum/#!topic/scala-user/_PodIqLmGC8

[scala-user] What's the state of Scala.NET?
; http://grokbase.com/t/gg/scala-user/131pet3xr5/whats-the-state-of-scala-net

아쉽군요. ^^ IKVM을 통해 우회적으로 스칼라를 구동할 수 있다고는 하지만,

Scala on .NET via IKVM
; http://tountas-software.blogspot.kr/2010/07/scala-on-net-via-ikvm.html

저 같은 닷넷 매니아에게도 저건 왠지 몹쓸 시도 같습니다. ^^;




참고로, 제가 읽은 책입니다.

도서 쉽게 배워서 빨리 써먹는 스칼라 프로그래밍
; http://www.yes24.com/24/Goods/8744130?Acode=101

실습이 대체로 어렵진 않았는데 다음의 코드 실행에서 걸렸습니다.

object Main extends App 
{
  override def main(args: Array[String]) 
  {
    lazy val words = scala.io.Source.fromFile("c://temp/ConsoleApplication1.sln").mkString
    println(words)
  }
}

실행해 보면 이런 예외가 발생합니다.

Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
    at java.nio.charset.CoderResult.throwException(Unknown Source)
    at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    at sun.nio.cs.StreamDecoder.read(Unknown Source)
    at java.io.InputStreamReader.read(Unknown Source)
    at java.io.BufferedReader.read1(Unknown Source)
    at java.io.BufferedReader.read(Unknown Source)
    at java.io.Reader.read(Unknown Source)
    at scala.io.BufferedSource.mkString(BufferedSource.scala:96)
    at Main$.words$lzycompute$1(Main.scala:20)
    at Main$.words$1(Main.scala:20)
    at Main$.main(Main.scala:21)
    at Main.main(Main.scala)

자바에 익숙한 분들은 금방 원인을 알겠지만, 제 경우에는 감을 못잡았는데요. 다행히 아래의 글에 그 원인이 나옵니다.

How to read a text file with mixed encodings in Scala or Java?
; http://stackoverflow.com/questions/13625024/how-to-read-a-text-file-with-mixed-encodings-in-scala-or-java

따라서, 다음과 같이 명시적으로 인코딩 설정을 해주면 됩니다.

import scala.io.Codec
import java.nio.charset.CodingErrorAction

object Main extends App 
{
  override def main(args: Array[String]) 
  {
    implicit val codec = Codec("UTF-8")
    codec.onMalformedInput(CodingErrorAction.REPLACE)
    codec.onUnmappableCharacter(CodingErrorAction.REPLACE)

    lazy val words = scala.io.Source.fromFile("c://temp/ConsoleApplication1.sln").mkString
    println(words)
  }
}

한 가지 아쉬운 점은 UTF-8 인코딩을 지정해도 BOM이 붙은 파일의 경우 여전히 BOM 마크를 떼지 않고 포함한다는 것입니다. 그래서 BOM이 있는 파일을 읽을 때는 다음과 같이 "?" 문자가 출력됩니다.

?
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
...[생략]...
EndGlobal

회사 동료가 UTF-8 인코딩의 경우 표준에는 BOM을 붙이지 않는다고 합니다. (검색해 보니 그 말이 맞더군요. ^^)




전체적으로 Scala 책을 한번 읽어 본 소감은... 뭐랄까? Scala 언어가 분명 "함수형 + OOP"의 성격을 지니고 LISP와 같은 함수형 언어들에 비해 쉽다는 것은 분명하지만 여전히 주류 언어로 되기에는 개념이 어려운 것은 사실입니다. (제가 C#만 고집해서 그런 걸까요? ^^)

Scala 언어에 대해 흔히 말하기를 "단어가 적어서 생산성 향상으로 이뤄진다"는 것이 가장 눈에 띄는 선전 문구인데요. 사실... 이것은 양날의 검과 같습니다. 가령 물리학에서 열역학 제 2법칙을 다음과 같이 간단하게 썼다고 해서 누가 이 말 뜻을 제대로 이해하겠습니까?

열적으로 고립된 계의 총 엔트로피가 감소하지 않는다는 법칙

그랬으면 이런 위키백과 글은 씌여지지도 않았을 것입니다.

열역학 제2법칙
; http://ko.wikipedia.org/wiki/%EC%97%B4%EC%97%AD%ED%95%99_%EC%A0%9C2%EB%B2%95%EC%B9%99

짧게 표현했다고 해서 모두 쉬운 것이 아니라는!

정리해 볼까요?

개인적으로 최근의 Swift 언어를 비롯해서 F#, Java, Objective-C, Scala, Clojure, Python, PHP 등의 언어를 그야말로 수박겉핡기 식으로 책 한권 보는 수준 정도만 학습해 봤는데요. (그 외에 주력 언어인 C#을 비롯해서 Assembly, C/C++, Javascript 까지 합치면 저도 꽤나 돌아다닌 것 같습니다. ^^) 하지만, 모든 언어를 통달하기에는 인생이 너무 짧으므로. 제가 여러분들에게 혹시나 조언을 드릴 위치가 조금이라도 된다면 이렇게 말하고 싶습니다.

  1. 전문 개발자로써 C/C++ 언어는 꼭 하시기 바랍니다. 어셈블리 만큼은 아니겠지만 그래도 C/C++만 어느 정도 할 줄 알아도 시스템에 대한 기본 이해력이 보다 더 향상됩니다.
  2. Virtual Machine 위에 올라가는 언어를 하나 정도는 마스터하세요. C/C++ 언어는 분명 강력하지만 모든 프로젝트를 C/C++로 하기에는 인생이 너무 짧습니다. Java나 C#과 같은 GC 헤택을 받는 언어를 배운다면 여러분들의 생산성에 날개가 달릴 것입니다.
  3. 그 외에, 혹시나 또 다른 언어를 위의 2개 언어만큼 잘하고 싶은 마음이 들고 여유가 생긴다면? 저는 Python을 권하고 싶습니다. 스크립트 성격도 겸하고 있으며 여러 모로 C/C++과 Java/C#과 같은 언어와 함께 배워두면 유용하게 쓸 것 같습니다.

저는 그래서, 이것으로 '언어 건드리기'는 (당분간 혁신적인 무언가가 없는 한) 이쯤에서 접고, 이제부터는 짬이 나는대로 Python 언어를 좀 더 배워볼까 합니다. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2014-10-02 04시15분
오픈북 프로젝트 - 양질의 컴퓨터 문서 공급 프로젝트
; http://itguru.tistory.com/201
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13608정성태4/26/202418닷넷: 2249. C# - 부모의 필드/프로퍼티에 대해 서로 다른 자식 클래스 간에 Reflection 접근이 동작할까요?파일 다운로드1
13607정성태4/25/2024203닷넷: 2248. C# - 인터페이스 타입의 다중 포인터를 인자로 갖는 C/C++ 함수 연동
13606정성태4/24/2024220닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/2024487닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/2024554오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/2024754닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/2024825닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/2024872닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/2024902닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024878닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024906닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/2024889닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/20241077닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/20241056닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241072닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241088닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241226C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241201닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241081Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241158닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241272닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신 [2]파일 다운로드1
13587정성태3/27/20241172오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241341Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241145Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
13584정성태3/26/20241273개발 환경 구성: 708. Unity3D - C# Windows Forms / WPF Application에 통합하는 방법파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...