コミケ告知

サークル活動の詳細は circle タグの記事へ。
ラベル Scala の投稿を表示しています。 すべての投稿を表示
ラベル Scala の投稿を表示しています。 すべての投稿を表示
2015年9月13日日曜日

tryする末尾再帰関数が普通には書けないScala

TL;DR

try~catch内で値を返す再帰関数を書くには、scala.util.Tryを使う。

説明


Scalaでは末尾再帰関数は最適化してくれるし、それをtailrecアノテーションでチェックすることができます。(最適化が効かない場合にコンパイルエラーが出るようになる)
@scala.annotation.tailrec
def f(n: Int): Int = {
  ...  // (略)
  f(n - 1)
}
ただこれ、try~catchを付けて、そこで値を返そうとするとうまくいかないんですよね~
@scala.annotation.tailrec
def f(n: Int): Int = {
  try {
    ...  // (略)
    f(n - 1)
  } catch {
    // どの場合も返す型は正しいものとする
  }
}
scalac Main.scala
Main.scala:3: error: could not optimize @tailrec annotated method f: it contains a recursive call not in tail position
  def f(n: Int): Int = {
エラーメッセージも正しくなくてなんだこりゃって感じですが、stackoverflowに回答がありました。

何度も回答がEditされていますが、その一番下。try~catch節ではなく、scala.util.tryを用いることで回避できるようです。
@scala.annotation.tailrec
def f(n: Int): Int = {
  scala.util.Try(例外の出る処理内容) {
    case Success(処理の返り値) => ...
    case Failure(e: 例外の型) =>
    case Failure(e: 例外の型) =>
  }
}

知っていて最初からこれで書けば面倒くさいことはないんだけど…Scala、あちこち珍妙なとこあるよな。

2015年9月1日火曜日

Akkaのsenderは値ではない

久々に使うと忘れがちなのでメモ。

AkkaのActorは、メッセージ受信時にはその送信元を示すActorRefをsenderで取れます。メッセージを送り返したり、デバッグ時に表示させたり、何かと便利です。
def receive = {
  case x => sender ! x  // echo
}
しかしこのsender、Futureで使おうとすると望み通りの挙動をしません。表示させてみると、送信元とは違う値になっています。(deadLetters宛になる)
Future {
  sender ! myFunc(x)  // NG
}
こういうときは、一時的に別の定数に入れて使うか…
val dst = sender
Future {
  dst ! myFunc(x)  // OK
}
最後に結果を返したいだけなら、pipeToを用いるか。
Future {
  myFunc(x)
} pipeTo sender

senderとは何なのか

senderはcontext.senderを呼び出すようになっていて、さらに追っていくとActorCellの実装に辿り着きます。
  final def sender(): ActorRef = currentMessage match {
    case null                      ⇒ system.deadLetters
    case msg if msg.sender ne null ⇒ msg.sender
    case _                         ⇒ system.deadLetters
  }
これは変数ではなくメソッドであるので、sender と記述したところに制御が到達したタイミングで、初めて処理が行われます。ちなみにvar currentMessageを弄っているのも同じActorCell内で…
  final def invoke(messageHandle: Envelope): Unit = try {
    currentMessage = messageHandle
    cancelReceiveTimeout() // FIXME: leave this here???
    messageHandle.message match {
      case msg: AutoReceivedMessage ⇒ autoReceiveMessage(messageHandle)
      case msg                      ⇒ receiveMessage(msg)
    }
    currentMessage = null // reset current message after successful invocation
  }
  //  以下略…
まずcurrentMessageがセットされたのち、システム側で処理されるAutoReceivedMessage以外であれば、receiveMessageからActorのおなじみreceiveメソッドの処理へ。終わったら戻ってきてnullに戻します。(普通にnull使うんだ… 初期値が _ だからnullで統一してるんだな)
Futureの処理がどこかで走るときには、このメッセージ受信による処理駆動パスとは異なるので、 currentMessage == null であり、 sender()はdeadLettersを返すのですね。

カッコ省略のデメリット?

仕組みが分かっていない段階で誤った使い方をしてしまった原因のひとつが、引数なしメソッドのカッコが省略されていることでした。サンプルでも基本的に省略されているから、そもそも最初はメソッドだと思っていなかったよ…(´・ω・`)
記述が簡潔!の思想に走りすぎるとデメリットもありますよ、ということで。
2015年8月10日月曜日

scalikejdbc-mapper-generatorでテストを生成しない方法

TL;DR

generator.testTemplate
に無効な値を入れる。空白でよい。

本文


 ScalaでSQLを扱うときの選択肢のひとつであるScalikeJDBC。黒魔法Slickよりは何が起きているか理解しやすいので、せいぜいJavaのORMの3倍くらいの難易度に収まっていて、人間でも使える感があるライブラリです。
 機能のひとつに、既存のDBに接続して、その内容に合うようにインターフェイスを生成してくれるものがあります。ライブラリは scalikejdbc-mapper-generator として分かれており、ScalikeJDBCではReverse Engineeringという機能名で呼ばれます。Slickの同等機能はSCHEMA CODE GENERATION ですかね。

 このライブラリはテストコードも吐くようになっていますが、これがそのままでは通らなくて外したい、と思うことがあるでしょう。そんなときには、
project/scalikejdbc.propertiesgenerator.testTemplate に、無効な値を設定すれば、出力されないようです。ソースコードではscalikejdbc/mapper/CodeGenerator.scala def specAll() あたり。
2014年12月5日金曜日

Scala標準のFutureと並列コレクションの実行コンテキスト

この投稿はScala Advent Calendar 2014の5日目の記事です。4日目はmeganemuraさんScalastyle の導入 でした。
5日に出先から戻って以降ダウンしていた影響で、公開が翌朝になっております。すいません。

記事のテーマはシンプルで、Scalaの標準ライブラリの中で勝手にうまいことやってくれる(らしい)並列・非同期処理について、実行されるスレッドがどうなっているのか調べてみるものです。

Future


どこのFutureチュートリアルでも基本的に、 import ExecutionContext.Implicits.global をとりあえず書きましょう、と但し書きしてスタートします。これがデフォルトのFuture用の実行コンテキスト。 実行コンテキストの指定をしなかった場合 Cannot find an implicit ExecutionContext と怒られます。

ExecutionContext.Implicits.global の実装は、object Implicitの中にimplicit lazy val global: ExecutionContextExecutorがあって…中略、辿っていくと最終的に、以下の部分に辿り着きます。2.11.4では scala/concurrent/impl/ExecutionContextImpl.scala 内。
    try {
      new ForkJoinPool(
        desiredParallelism,
        threadFactory,
        uncaughtExceptionHandler,
        true) // Async all the way baby
    } catch {

java.util.conncurrentにあるForkJoinPoolですね。
デフォルトのものを使った場合の挙動は以前確認してみたのですが、最大スレッド数=CPU数としてForkJoinスレッドを扱う、無難な実装であるようです。


並列コレクション (parallel collection)


listやmap等のコレクションに対し、par を呼び出すことで簡単に並列処理になるよ!というやつです。
x: List[Int] =  // なにかListがあるとして…
scala> x.map(_ + 1)  // 普通のmap
scala> x.par.map(_ + 1)  // 並列版

基本的な説明も使い方も、公式のドキュメントにあります。設定は「並列コレクションの設定」のページ。特に実行環境を何も指定せず、おもむろに par を使っても、デフォルトの設定により実行されます。Futureと違って怒られない。

デフォルト以外の設定をする方法


Futureが要求するのはscala.concurrent.ExecutionContextExecutor で、並列コレクションが要求するのはscala.collection.parallel.TaskSupportなので微妙に違いますが、大したことはありません。

scala> import scala.concurrent._
scala> val pool = new forkjoin.ForkJoinPool(4)

pool: scala.concurrent.forkjoin.ForkJoinPool = scala.concurrent.forkjoin.ForkJoinPool@7f39e4a3[Running, parallelism = 4, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]
並列コレクションはtasksuppoortに設定。
scala> import scala.collection.parallel
scala> val pc = parallel.mutable.ParArray(1, 2, 3)

pc: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3)

scala> pc.tasksupport = new scala.collection.parallel.ForkJoinTaskSupport(pool)

pc.tasksupport: scala.collection.parallel.TaskSupport = scala.collection.parallel.ForkJoinTaskSupport@81df807
Futureは、object ExecutionContextを使ってなんとか。
scala> implicit val ece: ExecutionContextExecutor = scala.concurrent.ExecutionContext.fromExecutor(pool)

ece: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@2bacfa90

これでどちらも好きに設定できそうです。



この投稿はScala Advent Calendar 2014の5日目の記事でした。
6日目はkawachiさんによるscalac にもっと警告してもらう です。
2014年10月13日月曜日

Scalaの実行コンテキストとFuture, blocking

ScalaのFutureというのは、下から(プロセッサに近い方からの)目線でいえば、処理をスレッドプールに丸投げする仕組みです。.NETにも似たような仕組みがありますね。

参考:Scala公式ドキュメント Futureの項目 (en / jp)

Futureの実行環境として、Scalaではscala.concurrent.ExecutionContext.Implicits.global というものがあり、implicitなExecutionContextとして、デフォルトでよさげなものを用意してくれます。このExecutionContextの挙動を確かめるために、ちょっとしたコードを書きました。
基本は、第一引数で指定した数のFutureを生成して走らせるだけです。Future内では、実行タイミングとスレッド番号を表示します。
% scala FutureBehaviorChecker.scala 1
Processors: 8
Thread active: 3
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   27 ->   228] at  10
% scala FutureBehaviorChecker.scala 6
Processors: 8
Thread active: 8
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   28 ->   228] at  10
Finished: 05 [   31 ->   231] at  14
Finished: 02 [   31 ->   231] at  13
Finished: 03 [   31 ->   231] at  16
Finished: 04 [   31 ->   231] at  17
Finished: 01 [   31 ->   231] at  12

ExecutionContext.Implicits.globalの挙動

スレッドプール内のスレッド数は、プロセッサ数と同じだけの上限を持つようです。
% scala FutureBehaviorChecker.scala 10 
Processors: 8
Thread active: 9
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   33 ->   234] at  10
Finished: 04 [   37 ->   237] at  14
Finished: 03 [   37 ->   237] at  13
Finished: 05 [   37 ->   237] at  15
Finished: 02 [   37 ->   237] at  12
Finished: 01 [   36 ->   236] at  11
Finished: 06 [   37 ->   237] at  16
Finished: 07 [   37 ->   237] at  17
Finished: 08 [  246 ->   446] at  10
Finished: 09 [  246 ->   446] at  14
9個目以降は、全スレッドがブロックしているので詰まってますね。
まあデフォルトなんてこんなものか。と自前のExecutorContext指定の方法を調べかかりましたが、そこに手を出す前にもっと簡単な方法がありました。

blockingの指定

本家のドキュメント内ではさらりと流されていますが、ブロッキングしてしまうような迷惑なFutureに対しては、明示的にブロッキング動作をするものだと指定できるようです。

参考: multithreading - Asynchronous IO in Scala with futures - Stack Overflow

自作のテストコードでは、第二引数に何か与えると、Thread.sleepをblockingで囲んだコードが走ります。
% scala FutureBehaviorChecker.scala 10 1
Processors: 8
Thread active: 12
Current Thread: 1
Mode: sleep with blocking{}.
Finished: 04 [   33 ->   234] at  15
Finished: 06 [   33 ->   234] at  16
Finished: 07 [   34 ->   234] at  17
Finished: 01 [   33 ->   234] at  11
Finished: 09 [   35 ->   235] at  19
Finished: 05 [   33 ->   234] at  14
Finished: 00 [   29 ->   234] at  20
Finished: 08 [   35 ->   235] at  18
Finished: 02 [   33 ->   235] at  12
Finished: 03 [   33 ->   234] at  13

使用するスレッド数が増えてますね。長くなるのでわざわざここには貼りませんが、100個同時に走らせれば100スレッド生成されるようです。スレッドを立てるので使用するリソースは増えるものの、全体がブロックすることはなくなります。
この大量に生成されるスレッドは、Futureごとにスレッドをひとつ立てるのではなく、あくまでもスレッドプールに増えるものです。Future実行に使用したスレッドは一定時間ごとにじわじわとshutdownされていきます。Futureを使った後、定期的にスレッド数をprintしてみると、じわじわと減っていくのがわかります。


まとめ

  • Futureが走るスレッド数は有限
  • ブロックする操作 or 時間がかかる操作なら、とりあえずはblockingをつける
ブロッキング操作するFutureが多い場合は、java.util.concurrent.Executors関連調べて、もっとまじめに実行コンテキストの管理をした方が良いのではないかと思います。ブロックする操作の先にある何か(DBやネットワーク接続等)で扱える並列性よりもたくさん並べても、意味ないので…。
プロトタイプや遊びで組むぶんには、blockingに頼ってしまってもいいかな。
2014年10月11日土曜日

Akkaの挙動確認用の小物を作った

AkkaのActorスケジューリング周りの挙動を確認するための、ちょっとしたものを作りました。

概要

Actorの数、OSスレッドの数、Actor1個あたりに飛ばすメッセージ数を指定して回し、簡単なレポートを出力します。Actorのメッセージハンドリングが、どのスレッドでどんな順番で実行されたのかが表示されます。
適当に時間がかかるように、Actorはメッセージを受け取るごとにフィボナッチ数を求めています。この実験では別にsleepでも良いんですが、後々試したいことがいくつかあることと、OSやVMによるスレッドのスケジューリングに手を出したくないことから、この方法にしました。

Akkaの設定

参考:Configuration — Akka Documentation

スレッド数の設定

スレッド数は固定値を指定するものではなく「factor」「parallelism-min」「parallelism-max」の3項目と、実行環境で認識されたプロセッサー数によって決定します。まず最初に使われるのがfactorで、(プロセッサー数 * factor)を切り上げた値が用いられます。その後、parallelism-minparallelism-maxの指定範囲内にない場合は、指定範囲に収まるように値が補正されます。minよりmaxの方が小さい場合、maxが優先されるようです。

あくまでもfactorで計算された値が基本であるため、max設定値だけ大きくしてもスレッドは増えません
このテストプログラムでは、引数-apf, -apmin, -apmaxによって、この3項目を設定可能です。

スループットの指定

Actorがスレッドを手放すまでに処理するメッセージの数を設定するのが、akkaのthroughputです。パッと見では、用語から挙動を想像するのが難しいような気がします。

AkkaのActorスケジューリングに用いられる単位は、メッセージです。Actorが(receiveで)メッセージを受け取ると、どこかのスレッドに割り当てられ、receiveのブロックから抜けると、Akkaのシステム側に制御を委ねます。以下の例では、Msg1を受信したらdoFoo()を実行して終了、Msg2を受信したらdoBar1()とdoBar2()を実行して終了。
class HogeActor extends Actor {
  override def receive = {
    case Msg1 =>
      doFoo()
    case Msg2 =>
      doBar1()
      doBar2()
  }
}
スレッドを明け渡すまでに、メッセージをいくつ連続で処理するかを示す設定値がthroughputです。メッセージがActorのメールボックスに5個届いていたとして、throughputが5以上あれば、一気に全部処理します。throughputが1であれば、1個処理したところで、Akkaのシステムに一度制御を返します。他にメッセージ処理を待っているActorがいれば、そちらにスレッドを譲ることになります。
スレッド上で走るActorの入れ替えにはコストがかかるので、一気に走り続けた方が性能面では有利です。しかし、あるActorが居座ったままだと、他のActorがいつまで経っても処理を始められないかもしれません。Configuration説明ページのコメントに set to 1 for as fair as possible とあるように、このパラメーターはthroughputとfairnessのトレードオフです。ここまで説明してようやく、パラメーター名の意味がわかります。
throughputパラメーターは、冒頭のテストプログラムでは -at で設定できます。メッセージの数を多めに、スレッドの数をActorの数より少なく設定すると、何がどうなるのか観察できます。

補足

各WorkerActorの始動に1つメッセージを消費しているため、最初の1サイクルはメッセージ1個分ずれます。
2014年9月7日日曜日

ScalaMatsuri 2014 参加記録

ScalaMatsuri。昨年はScala Conference in Japanという普通~の名前だったのに、突飛な名前になっていました。今年は1日目がカンファレンス、2日目がアンカンファレンス。

会場

会場となったサイバーエージェントさんのセミナールームは、電源環境・無線環境とも非常に快適。無理やりケチをつけるならば、どこから辿り着くのかさっぱりわからない点くらいですかね。探せば画像付きの案内図が見つかるものの、カンファレンスのページからは、13Fという情報しか得られないし…

内容

もはや小田好先生となってしまった設計者Martin Odersky氏を筆頭に、今年もかなり実績のある方々が参加。でも個人的にはそっち方面よりも、はてな・LINE・GREE等々最前線企業での使用例が出されて、システムアーキテクチャ・ソフトウェアの選択(ORMやテンプレートエンジン等)・導入の様子などが見られた方にありがたみを感じました。もはや導入 自体が珍しい段階は通りすぎて、使っている人が何かしらの課題・アイデアを抱えて参加している印象を受けました。

英語

海外からのゲストスピーカーを招いているため、一応スライドは英語ですが、発表や案内は日本語を使えない人以外は基本的に日本語。なぜか日本人同士が英語で質疑&応答を行い全然通じない場面があり失笑を買った場面がありましたが、基本的には各自得意な言語で淡々とやる感じでした。私事ですが今の勤務先では、英語頑張るのは結構だけど、英語を覚えるのと仕事するのは切り離せと釘を刺されております。コミュニケーションの質を下げてはいけない。

英語ネイティブスピーカーのセッションには、なんと文字による同時通訳つき。運営の方々頑張りすぎでは…。進行・質疑応答補助・食事案内等、すごい運営のパワーを感じるカンファレンスでした。もうちょっと力抜いても良いのでは?と心配してしまいます。

総括

覚えるべきこと、Scala周辺に限っても無限にあるなあというのを再実感。
カンファレンスには色々ありますが、ScalaMatsuriは「色々やってみたくなる」「色々覚えなければとプレッシャーがかかる」という、かなりプラス方向の意識が得られました。もちろん意識だけでなくて、知識も業務上のノウハウも得られたはずだ…!(後で資料読み直そう)
2013年4月15日月曜日

Cygwin+SBTでEnterキーが効かない場合の対処

現象

Cygwin上でsbtを起動は出来るが、Enterキーが効かないので何もできない。


原因

ターミナルの設定とSBT側の処理が合っていないのが原因。sbt-launch.jarを実行するときに、-Djline.terminal=jline.UnixTerminal を引数に渡せばよい。

Windows用のsbt…すなわち、msiでセットアップされるsbtや、アーカイブ中のwin-sbtには、$TERMがxtermのときだけ前述のオプションを渡すという中途半端な処理が書いてあるのだが、少しでも違うとそちらの分岐に行かない。(たとえばminttyのxterm-256color)


対処

  • sbt.batをいじって、必ず引数が渡るようにする
    •  if [ "_$TERM" = "_xterm" ]; の判定文をいじるとか
    • "$JAVA_CMD"のあとに直接書いちゃうとか (cmd.exeから呼んだときに大丈夫かどうか知らないが)
  • あるいは、環境変数 $JAVA_OPTS に指定する

2013年2月9日土曜日

RxJavaをScala(+SBT)から試してみる

# はてなダイアリーから移動した記事です。あまり真面目に整形していません。

C#のReactive ExtensionsのJava版*1であるRxJavaが、NetflixからApache License Version 2.0で公開されていました。

Rxについては

SBTのコンフィグレーション

rxjava-scalaへの依存性を書けばOK。依存しているrxjava-coreも取ってきてくれるので。

libraryDependencies += "com.netflix.rxjava" % "rxjava-scala" % "0.5.+"

最初見たときは0.5.0でしたが、今見たら0.5.1でした。

動作確認

ScalaAdaptorでテストに使われているサンプルほぼそのまま*2。くだらないけど、これが動かなければ設定がおかしいので、まずはここから。

    Observable.toObservable("1", "2", "3").take(1).subscribe(Map(
      "onNext" -> ((callback: String) => {
        println("testTake: callback = " + callback)
      })
    ))
run
[info] Running info.moccos.Main
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
testTake: callback = 1

動いているようです。
SLF4Jが邪魔ですが、ログは今は出なくてもいいので見なかったことに。(以後のログでも省きます)

java.lang.RuntimeException: Unsupported closure type というエラー

サポートしていない型をObservable.toObservableに渡すと、そんな型知らんとRuntimeExceptionを飛ばされます。最初、rxjava-core(ScalaのAdaptorがない)を引っ張ってきていたときに遭遇しました。

もう少し使ってみる

    val xs = 1 to 10
    Observable.toObservable(xs)
      .take(3)
      .subscribe(Map(
        "onNext" -> ((x: Int) => {
          println("testTake: callback = " + x)
        })
      ))
[info] Running info.moccos.Main
[error] (run-main) java.lang.ClassCastException
java.lang.ClassCastException
[trace] Stack trace suppressed: run last compile:run for the full output.
java.lang.RuntimeException: Nonzero exit code: 1
        at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) Nonzero exit code: 1

ぬ?
ここでonNextで拾う型をとりあえずAnyにしてみると…

testTake: callback = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

お、おう。テストコードにあったようなtupleだと、ScalaAdapterが直接変換してくれて上手くいきますが、コレクションの変換はまだ実装されていないみたいです。明示的にJavaの理解できる型を渡してあげないと。

    val xs: java.util.List[Int] = 1 to 10

または

    Observable.toObservable[Int](xs)
[info] Running info.moccos.Main
testTake: 1
testTake: 2
testTake: 3

これはOK。ちなみにStreamの無限数列を渡したら、無限に数えます。push型=値を生成できる限りどんどんpushするのだから、そりゃ当然か。

使える操作

rx-coreのpackage rx.operatorsを見ればわかりそうです。

参考までに本家Rxのものは…もう2年半前で古い記事ですがこれを。

合成したり取得する値を選んだりという基本中の基本だけ備わっている状態です。それから、onCompletedって書いても動いてくれないみたい。まだ趣味プロジェクトの範囲内かなあ。時間系が入ってくると面白いんですが。
pull requestにあるように、Netflixの狙い通り(?)にいくつか飛んできているので、興味を持った人たちによってじわじわと増えるのでしょう。*3

雑感

生まれたてです。既に実戦投入されたものを公開したわけではないので、これからみんなでがんばろうぜ!と煽っている段階ですね。
Scalaだと、Akka発のFutureが強力だし、元々マッチングも手軽に色々できるので、rxjavaすげー!世界が変わる!ということにはならないかもしれませんが、今後どうなるのか楽しみではあります。

*1:JVM版と呼ぶべきかどうか

*2:テスト文取って改行を足した。

*3:お前も参加しろと言われると、力不足ですまんと答えるほかない…

2012年7月12日木曜日

ByteBufferの挙動を確かめるには

# はてなダイアリーから移動した記事です。あまり真面目に整形していません。

java.nio.ByteBufferってクラスがあります。Byteの配列を直接扱うのはクールではない、という純情な感情から生まれたクラスに違いありません。たぶん。

putInt(x)や getFloat() のようなひとつ上のレイヤーのメソッドで値を出し入れ出来たり、asLongBuffer()などで特定型が並んだものとして扱えたりと、何かと便利です。

ただ、隠蔽されているメンバ変数、特にpositionの動きには、慣れるまでは翻弄されるかもしれません。メソッドによっては自動的にインクリメントしてくれたり、ByteBufferを受け取るメソッド内で読み取っていたりするので、何がどうなっているかわからずに使うと、はまる可能性があります。参照透明性とは真逆の存在ですね。仮にasReadOnlyBufferで変換しても、中でpositionやlimitは勝手に動くので。

対話環境を起動

こういうときは対話環境、すなわちコマンド打ったらその場で実行してくれるような環境で遊んでみるのが分かりやすいです。おもむろにscalaのREPL(対話環境)を起動!
Javaユーザーも、とりあえずScalaをインストールしましょう。一行ずつコマンド打つ程度なら、大して違うものでもないので大丈夫。

~ % scala
scala> import java.nio.ByteBuffer
import java.nio.ByteBuffer

scala> ByteBuffer.allocate(128)
res0: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=0 lim=128 cap=128]

返り値は自動的にresNに入ります。res0にByteBufferが確保できたので、以後この値を使います。
変数に入ると同時にStringとして表示してくれるのが、特に今回は有難いところです。position/limit/capacityの値がすぐ確認できます。

scala> res0.putInt(123)
res1: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=4 lim=128 cap=128]

scala> res0.putInt(456)
res2: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=8 lim=128 cap=128]

値を置くと勝手にpositionが進んでいますね。

scala> res0.putInt(0, 789)
res3: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=8 lim=128 cap=128]

index指定のput系ではposition変わらず。

scala> res0.position()
res4: Int = 8

scala> res0.position(4)
res5: java.nio.Buffer = java.nio.HeapByteBuffer[pos=4 lim=128 cap=128]

position()で現在のpositionを得られます。(scalaなので()要らないけど、しばらくはJava的表記)
引数ありのpositionを使うと、positionを動かせます。

scala> res0.getInt()
res6: Int = 456

scala> res0
res7: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=8 lim=128 cap=128]

scala> res0.getInt(4)
res8: Int = 456

scala> res0
res9: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=8 lim=128 cap=128]

getInt()でもpositionが自動的に移動。やはりindex指定ならばposition変わらず。

scala> res0.rewind()
res10: java.nio.Buffer = java.nio.HeapByteBuffer[pos=0 lim=128 cap=128]

rewindで先頭に巻き戻ります。でも返るのがBufferなので、若干びびります。

scala> res0.limit(4)
res11: java.nio.Buffer = java.nio.HeapByteBuffer[pos=0 lim=4 cap=128]

scala> res0.putFloat(1.5f)
res12: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=4 lim=4 cap=128]

scala> res0.putFloat(2.6f)
java.nio.BufferOverflowException

limitもpositionと同じような引数あり・なし版があり。limitより先に書きこもうとすると、溢れた扱いになります。

実行例がやたらと長くなりましたが、とにかくjavaいじるのにscala便利だぜってことで。

ついでにDatagramChannel

scala> import java.nio.channels.DatagramChannel
import java.nio.channels.DatagramChannel

scala> import java.net._
import java.net._

scala> val ch = DatagramChannel.open(StandardProtocolFamily.INET)
ch: java.nio.channels.DatagramChannel = sun.nio.ch.DatagramChannelImpl@11045dfe

resNが複数あると紛らわしいのでval chに入れてみた。
(Javaっぽく書こうとしていたことは忘れる。importのワイルドカードもちょっとJavaと異なる)

scala> res0.limit(100)
res16: java.nio.Buffer = java.nio.HeapByteBuffer[pos=4 lim=100 cap=128]

scala> ch.send(res0, new InetSocketAddress("localhost", 10000))
res17: Int = 96

scala> res0
res18: java.nio.ByteBuffer = java.nio.HeapByteBuffer[pos=100 lim=100 cap=128]

sendの返り値は、送信したByte数です。positionからlimitまで送信、そしてpositionは移動。
(自動インクリメントのputでデータを配置したあと、positionを巻き戻し忘れると…)