上一篇文章裏咱們簡單嘗試了在Scala裏編寫.NET應用程序。這個過程並不困難,由於彷佛Scala官方已經對此已經有較好的支持了。咱們要作的只是「獲取工具」,「編譯成IL」,最後再「生成程序集」便可。那麼,這些工具究竟作了些什麼,Scala究竟又是如何支持.NET平臺的,它的可用性究竟如何,咱們還須要進一步的分析及嘗試。html
如今看第一個問題。咱們知道從Scala源代碼生成IL文件的腳本是scalac-net.bat。若是須要了解它作的事情,最直接的方法莫過於查看其中的內容。若是要看明白它的代碼,可能須要咱們對cmd命令有些瞭解——不過我也只是略知一二罷了,若是您對其瞭解很少其實也沒有太大關係。通過合理推測,咱們知道scalac-net.bat自己不會有什麼功能,它只是調用編譯器而已。所以,這個腳本文件的職責,無非是收集參數並執行編譯器。因而咱們打開scalac-net.bat,在衆多for/if之中能夠發現它最後執行了這樣一個命令:java
%_JAVACMD% -Xbootclasspath/a:"%_BOOT_CLASSPATH%" %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.nsc.Main -target:msil %_ARGS%
那麼咱們再調用scalac-net.bat的時候這行命令到底是什麼呢?對於此類問題,咱們能夠再它前面加上ECHO命令,即:工具
ECHO %_JAVACMD% -Xbootclasspath/a:"%_BOOT_CLASSPATH%" %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.nsc.Main -target:msil %_ARGS%
ECHO能夠視爲cmd的print命令,咱們能夠用它來觀察和學習腳本。再次運行,即可以看到編譯器的調用方式了:學習
D:\scala-2.7.7.final\code> ..\bin\scalac-net.bat test.scala java -Xbootclasspath/a:"D:\SCALA-~1.FIN\bin\..\lib\scala-library.jar" -Xmx256M -Xms16M -Dscala.home="D:\SCALA-~1.FIN\bin\.." -Denv.classpath="" -Dmsil.libpath="D:\SCALA-~1.FIN\bin\..\lib\predef.dll;D:\SCALA-~1.FIN\bin\..\lib\scalaruntime.dll;D:\SCALA-~1.FIN\bin\..\lib\mscorlib.dll" -Dmsil.ilasm="c:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe" -cp "D:\SCALA-~1.FIN\bin\..\lib\mscorlib.dll;D:\SCALA-~1.FIN\bin\..\lib\predef.dll;D:\SCALA-~1.FIN\bin\..\lib\sbaz-tests.jar;D:\SCALA-~1.FIN\bin\..\lib\sbaz.jar;D:\SCALA-~1.FIN\bin\..\lib\scala-compiler.jar;D:\SCALA-~1.FIN\bin\..\lib\scala-dbc.jar;D:\SCALA-~1.FIN\bin\..\lib\scala-library.jar;D:\SCALA-~1.FIN\bin\..\lib\scala-swing.jar;D:\SCALA-~1.FIN\bin\..\lib\scalaruntime.dll" scala.tools.nsc.Main -target:msil test.scala
能夠看出,這是在運行一個java程序,而且提供了不少參數。不過參數不少,內容也很亂。不過亂的緣由在於其中對於各式命令或者庫文件的引用都使用的完整路徑。通過換行,相對路徑調整,並去除一些明顯無用的參數內容(如-cp,即classpath裏的dll文件),咱們發現其實大約這樣的:ui
D:\scala-2.7.7.final\code> ..\bin\scalac-net.bat test.scala java -Xbootclasspath/a:"..\lib\scala-library.jar" -Xmx256M -Xms16M -Dscala.home=".." -Denv.classpath="" -Dmsil.libpath="..\lib\predef.dll;..\lib\scalaruntime.dll;..\lib\mscorlib.dll" -Dmsil.ilasm="c:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe" -cp "..\lib\sbaz-tests.jar;..\lib\sbaz.jar;..\lib\scala-compiler.jar;..\lib\scala-dbc.jar;..\lib\scala-library.jar;..\lib\scala-swing.jar;" scala.tools.nsc.Main -target:msil test.scala
您能夠執行整理後的命令,效果一致。通過一番摸索,再配合scalac.bat -help的輸出,咱們能夠觀察出命令的具體意義,例如:spa
那麼假設咱們已經編譯生成了一個test.exe文件,如今使用.NET Reflector來觀察它的信息:scala
可見test.exe依賴另外三個程序集,它們按照依賴關係分別是:設計
看上去並無什麼問題,不是嗎?可是,通過簡單的思考,彷佛又不是那麼一回事情。比如,您是否以爲一個Scala程序的依賴實在少了一些?例如您平時寫程序時可否僅僅依賴mscorlib.dll,而不使用System.dll或System.Core.dll等其餘程序集?那麼,爲何Scala即可以僅僅基於mscorlib.dll而構建predef.dll呢?爲此,咱們簡單比較一下predef.dll與Java平臺上Scala的標準庫——scala-library.jar。首先是predef.dll:3d
其次是scala-library.jar中的定義:code
能夠看出,Scala標準庫中定義了比predef.dll中更多的類庫。例如Scala一直引覺得傲的Actor類庫,即scala.actors命名空間。換句話說,.NET平臺上的Scala並不支持Java平臺上的許多高級功能——這樣彷佛能夠理解爲何它只需依賴mscorlib.dll就足夠了。不過「標準類庫少」是壞事仍是好事倒也不能輕易下結論。
若是說這是壞事——類庫少天然是壞事。那麼「好事」又從何談起呢?個人理解是:Scala畢竟是爲Java平臺設計的語言,它本可沒必要對.NET提供支持。也就是說,.NET平臺只是Scala的「副業」。若是說,由於IL和Java Code相近(或者說有很大程度的「包含」關係),那麼編譯器在寫起來相對問題不大,但「類庫」就沒法討巧了。若是.NET類庫跟得太緊,那麼我反而要懷疑它的質量是否成熟。在使用Scala時,我主要關注的實際上是「編譯器」及最終生成的IL,我並無指望可以使用Scala在.NET平臺上編寫程序。對此,編譯器是否成熟對咱們來講可能更加劇要。所以,.NET類庫少也並非壞事——畢竟.NET Framework已經提供了足夠的功能,不是嗎?
是嗎?
若是您比較心細,您應該已經從第一幅圖中看出問題來了。我特地將焦點放在mscorlib.dll上,目的即是展現它的版本信息,即:
mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
若是您關注一下平時寫程序時所使用的mscorlib.dll,會發現它是這樣的:
mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
爲何會不同?那是由於Scala所使用的mscorlib.dll是「本身帶來的」,並非系統安裝的.NET Framework。那麼它到底是什麼呢?展開後即可一目瞭然:
由於它並非微軟提供的.NET Framework,而是Mono平臺提供的.NET類庫!若是您使用.NET Reflector來查看其中某些類庫的具體實現,會發現它和.NET Framework中實現有很明顯的不一樣(如字符串的鏈接操做)。
有朋友可能會想,這問題應該不大,只要在編譯時提供機器上安裝的程序集不就能夠了嗎?但問題是,微軟發佈的.NET Framework,他們都是依賴於mscorlib.dll——這是每一個.NET程序的核心,例如其中定義了一些基礎數據類型。想象一下,Scala編譯器使用的是Mono裏定義的String類型,那麼如何把它傳遞給MS .NET裏定義的方法呢?要知道後者使用的但是MS .NET裏的String!
通過多番嘗試,我沒法讓Scala編譯器使用MS .NET裏的程序集——即使是再簡單的case。固然,目前我還沒法肯定這是Scala編譯器的問題,亦或的確只是類庫的關係。不知道修改一下Scala的編譯器或是基於Mono進行編譯可否成功,我會再進行更多嘗試——若是某一天您發現我又寫了一篇「下」,而如今這篇變成了「中」……也是很是正常的事情。:)