This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Why does PartialFunction <: Function1?

6 replies
Kris Nuttycombe
Joined: 2009-01-16,
User offline. Last seen 42 years 45 weeks ago.

In a discussion in #scala this afternoon, the fact that Set[A] extends
(A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
up. It was pointed out that implementing something that is both a
Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
implemented due to the conflict between the erased types of Function1
in each respective case.

I hadn't thought about the fact that PartialFunction <: Function1
before, but now this seems like a very confusing decision to me. I
would expect it to be the other way round, since the way it currently
is means that a class of runtime exceptions is introduced for the
situation where a PartialFunction instance is passed to a function
that expects a Function1 and hence doesn't check isDefinedAt.

Now, of course, having Function1 extend PartialFunction directly won't
work because you can't overload apply(A) with different return types.
However, one could have something like the following:

trait PartialFunction[A,B] {
def papply(a: A): Option[B]
}

trait Function1[A,B] extends PartialFunction[A,B] {
def apply(a: A): B
override def papply(a: A) = Some(apply(a))
}

This would eliminate the need for runtime isDefinedAt checks, plug the
possible runtime exception hole, and even allow TreeSet[A] extends
Set[A] with Sequence[A].

So, why was it done the other way around? Can, and should, this be changed?

Kris

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Why does PartialFunction <: Function1?
Well, PartialFunction derives Function1 because Function1 doesn't define isDefinedAt. But since you can't pass a PartialFunction to something expecting a Function1, as it breaks the LSP, not to mention the code, then it should never have been a subclass of Function1.
Personally, I'd prefer Function1 to be a subclass of PartialFunction, with isDefinedAt overridden to always return true.

On Wed, Jul 29, 2009 at 7:12 PM, Kris Nuttycombe <kris [dot] nuttycombe [at] gmail [dot] com> wrote:
In a discussion in #scala this afternoon, the fact that Set[A] extends
(A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
up. It was pointed out that implementing something that is both a
Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
implemented due to the conflict between the erased types of Function1
in each respective case.

I hadn't thought about the fact that PartialFunction <: Function1
before, but now this seems like a very confusing decision to me. I
would expect it to be the other way round, since the way it currently
is means that a class of runtime exceptions is introduced for the
situation where a PartialFunction instance is passed to a function
that expects a Function1 and hence doesn't check isDefinedAt.

Now, of course, having Function1 extend PartialFunction directly won't
work because you can't overload apply(A) with different return types.
However, one could have something like the following:

trait PartialFunction[A,B] {
 def papply(a: A): Option[B]
}

trait Function1[A,B] extends PartialFunction[A,B] {
 def apply(a: A): B
 override def papply(a: A) = Some(apply(a))
}

This would eliminate the need for runtime isDefinedAt checks, plug the
possible runtime exception hole, and even allow TreeSet[A] extends
Set[A] with Sequence[A].

So, why was it done the other way around? Can, and should, this be changed?

Kris



--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.
Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: Why does PartialFunction <: Function1?
*... as then the conflict would be between ...

--j

On Wed, Jul 29, 2009 at 3:20 PM, Jorge Ortiz <jorge [dot] ortiz [at] gmail [dot] com> wrote:
Nitpick:

Your suggestion wouldn't allow TreeSet[A] extends Set[A] with Sequence[A], as then between PartialFunction[A, Boolean] (through Set[A]) and PartialFunction[Int, A] (through Sequence).

--j

On Wed, Jul 29, 2009 at 3:12 PM, Kris Nuttycombe <kris [dot] nuttycombe [at] gmail [dot] com> wrote:
In a discussion in #scala this afternoon, the fact that Set[A] extends
(A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
up. It was pointed out that implementing something that is both a
Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
implemented due to the conflict between the erased types of Function1
in each respective case.

I hadn't thought about the fact that PartialFunction <: Function1
before, but now this seems like a very confusing decision to me. I
would expect it to be the other way round, since the way it currently
is means that a class of runtime exceptions is introduced for the
situation where a PartialFunction instance is passed to a function
that expects a Function1 and hence doesn't check isDefinedAt.

Now, of course, having Function1 extend PartialFunction directly won't
work because you can't overload apply(A) with different return types.
However, one could have something like the following:

trait PartialFunction[A,B] {
 def papply(a: A): Option[B]
}

trait Function1[A,B] extends PartialFunction[A,B] {
 def apply(a: A): B
 override def papply(a: A) = Some(apply(a))
}

This would eliminate the need for runtime isDefinedAt checks, plug the
possible runtime exception hole, and even allow TreeSet[A] extends
Set[A] with Sequence[A].

So, why was it done the other way around? Can, and should, this be changed?

Kris


Kris Nuttycombe
Joined: 2009-01-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Why does PartialFunction <: Function1?

That's true. Should have thought more, but I think that the hierarchy
is still upside down.

Set[A] probably shouldn't extend PartialFunction[A, Boolean]; you
already have contains anyway, so it's kind of a superfluous syntactic
nicety.

Kris

On Wed, Jul 29, 2009 at 4:20 PM, Jorge Ortiz wrote:
> Nitpick:
>
> Your suggestion wouldn't allow TreeSet[A] extends Set[A] with Sequence[A],
> as then between PartialFunction[A, Boolean] (through Set[A]) and
> PartialFunction[Int, A] (through Sequence).
>
> --j
>
> On Wed, Jul 29, 2009 at 3:12 PM, Kris Nuttycombe
> wrote:
>>
>> In a discussion in #scala this afternoon, the fact that Set[A] extends
>> (A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
>> up. It was pointed out that implementing something that is both a
>> Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
>> implemented due to the conflict between the erased types of Function1
>> in each respective case.
>>
>> I hadn't thought about the fact that PartialFunction <: Function1
>> before, but now this seems like a very confusing decision to me. I
>> would expect it to be the other way round, since the way it currently
>> is means that a class of runtime exceptions is introduced for the
>> situation where a PartialFunction instance is passed to a function
>> that expects a Function1 and hence doesn't check isDefinedAt.
>>
>> Now, of course, having Function1 extend PartialFunction directly won't
>> work because you can't overload apply(A) with different return types.
>> However, one could have something like the following:
>>
>> trait PartialFunction[A,B] {
>>  def papply(a: A): Option[B]
>> }
>>
>> trait Function1[A,B] extends PartialFunction[A,B] {
>>  def apply(a: A): B
>>  override def papply(a: A) = Some(apply(a))
>> }
>>
>> This would eliminate the need for runtime isDefinedAt checks, plug the
>> possible runtime exception hole, and even allow TreeSet[A] extends
>> Set[A] with Sequence[A].
>>
>> So, why was it done the other way around? Can, and should, this be
>> changed?
>>
>> Kris
>
>

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: Why does PartialFunction <: Function1?
Nitpick:

Your suggestion wouldn't allow TreeSet[A] extends Set[A] with Sequence[A], as then between PartialFunction[A, Boolean] (through Set[A]) and PartialFunction[Int, A] (through Sequence).

--j

On Wed, Jul 29, 2009 at 3:12 PM, Kris Nuttycombe <kris [dot] nuttycombe [at] gmail [dot] com> wrote:
In a discussion in #scala this afternoon, the fact that Set[A] extends
(A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
up. It was pointed out that implementing something that is both a
Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
implemented due to the conflict between the erased types of Function1
in each respective case.

I hadn't thought about the fact that PartialFunction <: Function1
before, but now this seems like a very confusing decision to me. I
would expect it to be the other way round, since the way it currently
is means that a class of runtime exceptions is introduced for the
situation where a PartialFunction instance is passed to a function
that expects a Function1 and hence doesn't check isDefinedAt.

Now, of course, having Function1 extend PartialFunction directly won't
work because you can't overload apply(A) with different return types.
However, one could have something like the following:

trait PartialFunction[A,B] {
 def papply(a: A): Option[B]
}

trait Function1[A,B] extends PartialFunction[A,B] {
 def apply(a: A): B
 override def papply(a: A) = Some(apply(a))
}

This would eliminate the need for runtime isDefinedAt checks, plug the
possible runtime exception hole, and even allow TreeSet[A] extends
Set[A] with Sequence[A].

So, why was it done the other way around? Can, and should, this be changed?

Kris

Ricky Clarkson
Joined: 2008-12-19,
User offline. Last seen 3 years 2 weeks ago.
Re: Why does PartialFunction <: Function1?

I would like to understand why Set and Sequence extend PartialFunction.

2009/7/29 Jorge Ortiz :
> Nitpick:
>
> Your suggestion wouldn't allow TreeSet[A] extends Set[A] with Sequence[A],
> as then between PartialFunction[A, Boolean] (through Set[A]) and
> PartialFunction[Int, A] (through Sequence).
>
> --j
>
> On Wed, Jul 29, 2009 at 3:12 PM, Kris Nuttycombe
> wrote:
>>
>> In a discussion in #scala this afternoon, the fact that Set[A] extends
>> (A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
>> up. It was pointed out that implementing something that is both a
>> Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
>> implemented due to the conflict between the erased types of Function1
>> in each respective case.
>>
>> I hadn't thought about the fact that PartialFunction <: Function1
>> before, but now this seems like a very confusing decision to me. I
>> would expect it to be the other way round, since the way it currently
>> is means that a class of runtime exceptions is introduced for the
>> situation where a PartialFunction instance is passed to a function
>> that expects a Function1 and hence doesn't check isDefinedAt.
>>
>> Now, of course, having Function1 extend PartialFunction directly won't
>> work because you can't overload apply(A) with different return types.
>> However, one could have something like the following:
>>
>> trait PartialFunction[A,B] {
>>  def papply(a: A): Option[B]
>> }
>>
>> trait Function1[A,B] extends PartialFunction[A,B] {
>>  def apply(a: A): B
>>  override def papply(a: A) = Some(apply(a))
>> }
>>
>> This would eliminate the need for runtime isDefinedAt checks, plug the
>> possible runtime exception hole, and even allow TreeSet[A] extends
>> Set[A] with Sequence[A].
>>
>> So, why was it done the other way around? Can, and should, this be
>> changed?
>>
>> Kris
>
>

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Why does PartialFunction <: Function1?
And, furthermore, it's one excuse for not making Set co-variant. :-)

On Wed, Jul 29, 2009 at 7:25 PM, Kris Nuttycombe <kris [dot] nuttycombe [at] gmail [dot] com> wrote:
That's true. Should have thought more, but I think that the hierarchy
is still upside down.

Set[A] probably shouldn't extend PartialFunction[A, Boolean]; you
already have contains anyway, so it's kind of a superfluous syntactic
nicety.

Kris

On Wed, Jul 29, 2009 at 4:20 PM, Jorge Ortiz<jorge [dot] ortiz [at] gmail [dot] com> wrote:
> Nitpick:
>
> Your suggestion wouldn't allow TreeSet[A] extends Set[A] with Sequence[A],
> as then between PartialFunction[A, Boolean] (through Set[A]) and
> PartialFunction[Int, A] (through Sequence).
>
> --j
>
> On Wed, Jul 29, 2009 at 3:12 PM, Kris Nuttycombe <kris [dot] nuttycombe [at] gmail [dot] com>
> wrote:
>>
>> In a discussion in #scala this afternoon, the fact that Set[A] extends
>> (A => Boolean) and Sequence[A] extends PartialFunction[Int, A] came
>> up. It was pointed out that implementing something that is both a
>> Set[A] and a Sequence[A] (for example, TreeSet?) could not be properly
>> implemented due to the conflict between the erased types of Function1
>> in each respective case.
>>
>> I hadn't thought about the fact that PartialFunction <: Function1
>> before, but now this seems like a very confusing decision to me. I
>> would expect it to be the other way round, since the way it currently
>> is means that a class of runtime exceptions is introduced for the
>> situation where a PartialFunction instance is passed to a function
>> that expects a Function1 and hence doesn't check isDefinedAt.
>>
>> Now, of course, having Function1 extend PartialFunction directly won't
>> work because you can't overload apply(A) with different return types.
>> However, one could have something like the following:
>>
>> trait PartialFunction[A,B] {
>>  def papply(a: A): Option[B]
>> }
>>
>> trait Function1[A,B] extends PartialFunction[A,B] {
>>  def apply(a: A): B
>>  override def papply(a: A) = Some(apply(a))
>> }
>>
>> This would eliminate the need for runtime isDefinedAt checks, plug the
>> possible runtime exception hole, and even allow TreeSet[A] extends
>> Set[A] with Sequence[A].
>>
>> So, why was it done the other way around? Can, and should, this be
>> changed?
>>
>> Kris
>
>



--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland