Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 243. Scala 개발 환경 구성(JVM, 닷넷) [링크 복사], [링크+제목 복사],
조회: 24032
글쓴 사람
정성태 (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
정성태

... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
893정성태7/25/201027311오류 유형: 99. .NET 4.0 설치된 윈도우 7에서 SQL Server 2008 R2 설치 오류
892정성태7/9/201029079오류 유형: 98. 영문 윈도우에 한글 SQL Server 2008 R2 설치할 때 오류 [4]
891정성태7/8/201024933오류 유형: 97. MsiGetProductInfo failed to retrieve ProductVersion for package with Product Code = '{...}'. Error code: 1605. [2]
889정성태7/5/201026608.NET Framework: 179. Dictionary.Get(A) 대신 Dictionary.Get(A.GetHashCode())를 사용해서는 안 되는 이유 [1]
888정성태6/30/201024419오류 유형: 96. Hyper-V 연결 오류 - A connection will not be made because credentials may not be sent to the remote computer
887정성태6/23/201034259개발 환경 구성: 79. Hyper-V의 가상 머신에서 소리 재생 방법 [2]
886정성태6/23/201022452제니퍼 .NET: 14. ASMX, WCF 호출 모니터링 및 누수 확인
885정성태6/20/201023992개발 환경 구성: 78. COM+ 서버에서 COM+ 서버를 호출하는 방법
884정성태6/20/201026942제니퍼 .NET: 13. COM+ 서버 모니터링 [2]
883정성태6/18/201028850개발 환경 구성: 77. Appinit_Dlls로 구현한 환경 변수 설정 DLL [5]파일 다운로드1
882정성태6/17/201031655개발 환경 구성: 76. JKS(Java Key Store)에 저장된 인증서를 ActiveX 코드 서명에 사용하는 방법 [1]
881정성태6/14/201021085제니퍼 .NET: 12. COM+ 호출 모니터링 및 누수 확인
879정성태6/10/201023752제니퍼 .NET: 11. 소켓 모니터링 기능으로 본 ASP.NET의 소켓 풀링 기능 [1]
878정성태6/6/201023542제니퍼 .NET: 10. 소켓 모니터링 기능으로 본 WCF의 WSDualHttpBinding 성능 부하
877정성태5/31/201020265제니퍼 .NET: 9. 성능 관리 퀴즈 세 번째 문제 (닷넷 개발자 컨퍼런스)
876정성태5/31/201019706제니퍼 .NET: 8. 성능 관리 퀴즈 두 번째 문제 (닷넷 개발자 컨퍼런스) [2]
875정성태5/30/201021461제니퍼 .NET: 7. 성능 관리 퀴즈 첫 번째 문제 (닷넷 개발자 컨퍼런스)
873정성태5/19/201028319제니퍼 .NET: 6. 제니퍼를 위한 방화벽 설정
872정성태5/15/201027641제니퍼 .NET: 5. 제니퍼 서버 - NT 서비스로 구동시키는 방법
871정성태5/13/201034217VC++: 40. MSBuild를 이용한 VC++ 프로젝트 빌드파일 다운로드1
870정성태5/12/201025245제니퍼 .NET: 4. 닷넷 APM 솔루션 - 제니퍼 닷넷의 기능 요약 [2]
869정성태11/8/201926700오류 유형 : 95. WCF 인증서 설정 관련 오류 정리 [4]
865정성태5/5/201028986개발 환경 구성: 75. 인증서의 개인키를 담은 물리 파일 위치 알아내는 방법파일 다운로드1
864정성태5/4/201032844.NET Framework: 178. WCF - 사용자 정의 인증 구현 예제 [4]파일 다운로드1
863정성태5/4/201058765개발 환경 구성: 74. 인증서 관련(CER, PVK, SPC, PFX) 파일 만드는 방법 [1]파일 다운로드1
862정성태5/3/201020639제니퍼 .NET: 3. 제2회 닷넷 개발자 컨퍼런스에서 뵙겠습니다. ^^
... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...