- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Parameterised extractors
Sat, 2012-01-28, 15:07
I'm trying to build a library for implementing cryptographic
protocols. I have a class:
case class Encrypt(key:Key){
// decrypt cipherBytes with key, returning plaintext if successful
def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
}
I'd like to be able to use this in pattern matching as follows, where
bs:Array[Byte] is a ciphertext that is expected to be encrypted with
key:
bs match{
case Encrypt(`key`)(plain) => ... // do something with plain
}
But this gives an error: "'=>' expected but '(' found", at the opening
parenthesis before plain.
The following works, but is rather ugly:
val Enc = Encrypt(key)
bs match{
case Enc(plain) => ... // do something with plain
}
Is there some way to achieve the effect I'm after?
Sat, 2012-01-28, 20:11
#2
Re: Re: Parameterised extractors
I think his design is spot on, I use it in Scales as well and the standard lib regex matchers do the same.
Unfortunately there isn't another way to do it although I have seen a few threads about improving the situation.
On Jan 28, 2012 5:37 PM, "Sonnenschein" <peter.empen@arcor.de> wrote:> case class Encrypt(key:Key){
> // decrypt cipherBytes with key, returning plaintext if successful
> def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
> }
Case classes generate an unapply method in the companion object. In
your case that generated method has the signature
def unapply(e: Encrypt): Option[Key]
"def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] " you
have manually appended to Encrypt will never be matched.
What do you want to achieve with the match statement exactly? unapply
is simply meant to get the class parameter "key" so maybe your design
isn't appropriate?
val e = Encrypt(...)
e match {
case Encrypt(key) => // do something with key
case Encrypt(key) if key == "..." => // do something with key if it
satisfies the given condition
Peter
Sun, 2012-01-29, 10:51
#3
Re: Parameterised extractors
Hi Gavin, hi Chris,
it is still not obvious to me for what purpose Gavin uses "match".
What should "Encrypt(`key`)(plain) " do?
The statement "where bs:Array[Byte] is a ciphertext that is expected
to be encrypted with key" is also not clear to me. Do you mean "to be
encrypted (in future)" or "to have been encrypted" or "to be decrypted
(in future)"...?
I'd advocate full, workable code samples to give others the chance not
to miss anything.
Have a nice Sunday
Peter
Sun, 2012-01-29, 12:31
#4
Re: Re: Parameterised extractors
I would assume that the key creates an extractor which either returns plain text, when encrypted with that key or None when not. Perhaps the name Encrypt should be Unencrypted and it could be clearer.
The same approach let's you define a regex as an extractor with the groups in the regex as the input then - provided the regex matches - unapply returns the groups. In Scales it allows one to define an Xml element match when certain attributes are present.
In the above cases you need a starting input to perform the match/extraction logic against. Whereas a straight extractor only performs the unpacking these match as well.
The syntax suggestion "simply" moves the definition in-line which may be more appropriate when its a one-off match.
On Jan 29, 2012 10:43 AM, "Sonnenschein" <peter.empen@arcor.de> wrote:Hi Gavin, hi Chris,
it is still not obvious to me for what purpose Gavin uses "match".
What should "Encrypt(`key`)(plain) " do?
The statement "where bs:Array[Byte] is a ciphertext that is expected
to be encrypted with key" is also not clear to me. Do you mean "to be
encrypted (in future)" or "to have been encrypted" or "to be decrypted
(in future)"...?
I'd advocate full, workable code samples to give others the chance not
to miss anything.
Have a nice Sunday
Peter
Sun, 2012-01-29, 19:51
#5
Re: Parameterised extractors
On Jan 29, 9:43 am, Sonnenschein wrote:
> it is still not obvious to me for what purpose Gavin uses "match".
> What should "Encrypt(`key`)(plain) " do?
It should match a ciphertext that was encrypted with key; it should
bind plain to the corresponding plaintext. The unapply will decrypt
with key (I'm assuming symmetric crypto for simplicity); if that
succeeds, it will return Some applied to the result of the decryption;
if the decryption fails, it will return None.
> The statement "where bs:Array[Byte] is a ciphertext that is expected
> to be encrypted with key" is also not clear to me. Do you mean "to be
> encrypted (in future)" or "to have been encrypted" or "to be decrypted
> (in future)"...?
It is expected that it has been encrypted with the key. (In a
cryptographic protocol, one should never assume that a message
received is of the expected form.)
> I'd advocate full, workable code samples to give others the chance not
> to miss anything.
def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
val plainBytes = cipher.doFinal(cipherBytes);
Some(plainBytes)
} catch { case _ => None }
That works fine, except it seems necessary to write the pattern in the
slightly ugly form in my original message.
Sun, 2012-01-29, 20:21
#6
Re: Re: Parameterised extractors
On Sun, Jan 29, 2012 at 7:45 PM, Gavin Lowe <gavinlowe1@gmail.com> wrote:
Parameterised Extractors are definitely a palatable feature proposal. Here's some previous discussion:
http://www.scala-lang.org/node/10861 http://stackoverflow.com/questions/2411573/can-extractors-be-customized-with-parameters-in-the-body-of-a-case-statement-or/2454784#2454784
-jason
On Jan 29, 9:43 am, Sonnenschein <peter.em...@arcor.de> wrote:
> it is still not obvious to me for what purpose Gavin uses "match".
> What should "Encrypt(`key`)(plain) " do?
It should match a ciphertext that was encrypted with key; it should
bind plain to the corresponding plaintext. The unapply will decrypt
with key (I'm assuming symmetric crypto for simplicity); if that
succeeds, it will return Some applied to the result of the decryption;
if the decryption fails, it will return None.
> The statement "where bs:Array[Byte] is a ciphertext that is expected
> to be encrypted with key" is also not clear to me. Do you mean "to be
> encrypted (in future)" or "to have been encrypted" or "to be decrypted
> (in future)"...?
It is expected that it has been encrypted with the key. (In a
cryptographic protocol, one should never assume that a message
received is of the expected form.)
> I'd advocate full, workable code samples to give others the chance not
> to miss anything.
def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
val plainBytes = cipher.doFinal(cipherBytes);
Some(plainBytes)
} catch { case _ => None }
That works fine, except it seems necessary to write the pattern in the
slightly ugly form in my original message.
Parameterised Extractors are definitely a palatable feature proposal. Here's some previous discussion:
http://www.scala-lang.org/node/10861 http://stackoverflow.com/questions/2411573/can-extractors-be-customized-with-parameters-in-the-body-of-a-case-statement-or/2454784#2454784
-jason
Sun, 2012-01-29, 21:11
#7
Re: Re: Parameterised extractors
On Sun, Jan 29, 2012 at 17:17, Jason Zaugg wrote:
> On Sun, Jan 29, 2012 at 7:45 PM, Gavin Lowe wrote:
>>
>> On Jan 29, 9:43 am, Sonnenschein wrote:
>>
>> > it is still not obvious to me for what purpose Gavin uses "match".
>> > What should "Encrypt(`key`)(plain) " do?
>>
>> It should match a ciphertext that was encrypted with key; it should
>> bind plain to the corresponding plaintext. The unapply will decrypt
>> with key (I'm assuming symmetric crypto for simplicity); if that
>> succeeds, it will return Some applied to the result of the decryption;
>> if the decryption fails, it will return None.
>>
>> > The statement "where bs:Array[Byte] is a ciphertext that is expected
>> > to be encrypted with key" is also not clear to me. Do you mean "to be
>> > encrypted (in future)" or "to have been encrypted" or "to be decrypted
>> > (in future)"...?
>>
>> It is expected that it has been encrypted with the key. (In a
>> cryptographic protocol, one should never assume that a message
>> received is of the expected form.)
>>
>> > I'd advocate full, workable code samples to give others the chance not
>> > to miss anything.
>>
>> def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
>> val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
>> cipher.init(Cipher.DECRYPT_MODE, key);
>> val plainBytes = cipher.doFinal(cipherBytes);
>> Some(plainBytes)
>> } catch { case _ => None }
>>
>> That works fine, except it seems necessary to write the pattern in the
>> slightly ugly form in my original message.
>
>
> Parameterised Extractors are definitely a palatable feature proposal. Here's
> some previous discussion:
>
> http://www.scala-lang.org/node/10861
> http://stackoverflow.com/questions/2411573/can-extractors-be-customized-...
>
> -jason
They are also presently possible in a limited extent through string
templates, since the string is passed as parameter to the extractor.
> case class Encrypt(key:Key){
> // decrypt cipherBytes with key, returning plaintext if successful
> def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
> }
Case classes generate an unapply method in the companion object. In
your case that generated method has the signature
def unapply(e: Encrypt): Option[Key]
"def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] " you
have manually appended to Encrypt will never be matched.
What do you want to achieve with the match statement exactly? unapply
is simply meant to get the class parameter "key" so maybe your design
isn't appropriate?
val e = Encrypt(...)
e match {
case Encrypt(key) => // do something with key
case Encrypt(key) if key == "..." => // do something with key if it
satisfies the given condition
Peter