Theoretical feature for F# (discussion)

146 views
Skip to first unread message

Greg Rosenbaum

unread,
Mar 21, 2015, 5:59:02 AM3/21/15
to fsharp-o...@googlegroups.com
I made a writeup for a feature for F# that I think would be pretty neat. I don't think it will be realized (I barely think it is dignified enough for me to point this out), but I wanted to initiate a theoretical discussion about it, from a language design point of view. 

The feature pertains more to the object-oriented part of F#, but is also somewhat similar to type-classes in that it allows abstracting over similar types after they have already been created. It builds on statically resolved type parameters and member constraints, turning them into a more coherent type system feature.

Daniel Fabian

unread,
Mar 21, 2015, 8:39:24 AM3/21/15
to fsharp-o...@googlegroups.com
Hi Greg,

I read your article. And I have two questions:

1. If I understand your inline traits correctly, they are a way to define a type class / interface that then in turn can be used to generate proper member constraints in function using them and they provide syntactic sugar for the very counter-intuitive syntax of member constraint invocation expressions. Is that a good way of putting it?

2. Why would one need to (and want to) add the trait conformance as an explicit part of the type definition? Since they do not actually do anything, i.e. they do not provide any implementation, there should be no need to declare them explicitly on the type. On the other hand, if explicit declaration on a type is required, types cannot be retrofitted to conform to a trait. I would think, one might declare a trait to make sure a set of functions can be applied to the object - that's what is statically verified by the static member constraints after all. And once I define my trait, similar to defining a type abbreviation, conformance is verified on the call site. So in that sense the inline traits would be something similar to type abbreviations, just that they would define what members need to be present instead of naming an explicit type.

Your feedback is very welcome.

Yours Dany

--
--
To post, send email to fsharp-o...@googlegroups.com
To unsubscribe, send email to
fsharp-opensou...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/fsharp-opensource
---
You received this message because you are subscribed to the Google Groups "F# Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fsharp-opensou...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Isaac Abraham

unread,
Mar 21, 2015, 9:02:47 AM3/21/15
to fsharp-o...@googlegroups.com
I actually already raised a uservoice issue for making member constraints easier to use in order to make it easier to support static duck typing. I never actually came up with a solution for how to do it though!!

I would like to see this applied to e.g. Records as well e.g. A record must have field X - this might make composing records easier.

I'm sure I'm not the only person that has mentioned member constraints in the past so there does seem to be something worth discussing here.

From: Greg Rosenbaum
Sent: ‎21/‎03/‎2015 09:59
To: fsharp-o...@googlegroups.com
Subject: Theoretical feature for F# (discussion)

Greg Rosenbaum

unread,
Mar 21, 2015, 10:22:26 AM3/21/15
to fsharp-o...@googlegroups.com
1. Yes, that is exactly right. 

2. You don't need to declare trait conformance, but compile-time checking during type definition is very handy if you want to make sure your type conforms to a specific trait. A compiler error message would tell you which members your type lacks, and whether some members have the wrong signatures. Otherwise, you would have to go back and forth between the call site and the type, trying to awkwardly retrofit it. After all, the trait and the function that requires it might have easily been declared before the type.

Another reason is that if you intend to make your type a member of a specific trait in advance, you should be informed if subclassing it would break trait conformance, since this can be considered weird to people used to inheritance.

Yes, your description of inline traits as similar to type abbreviations is very concise. I wish I had thought of it myself.

Greg Rosenbaum

unread,
Mar 21, 2015, 10:42:41 AM3/21/15
to fsharp-o...@googlegroups.com
That's great! I wasn't expecting a lot of positive feedback. Could you link to the uservoice issue you raised? I can't seem to find it (I found a similar one, this one: https://fslang.uservoice.com/forums/245727-f-language/suggestions/6343928-allow-naming-of-member-constraints to which I commented, but it doesn't seem to have been raised by you)

Extending it to records is a good idea, I think. 

Isaac Abraham

unread,
Mar 21, 2015, 11:09:15 AM3/21/15
to fsharp-o...@googlegroups.com

From: Greg Rosenbaum
Sent: ‎21/‎03/‎2015 14:42
To: fsharp-o...@googlegroups.com
Subject: Re: Theoretical feature for F# (discussion)

Steven Taylor

unread,
Mar 26, 2015, 1:06:41 PM3/26/15
to fsharp-o...@googlegroups.com
It sounds like you want to extend the way F# resolves which record you are talking about flexibly to regular OO types?  

type DiscreteEventCounter = { mutable Total : int; mutable Positive : int; Name : string }

let newCounter nm = { Total = 0; Positive = 0; Name = nm }

You could use F# type signature .fsi files to define a trait now, and then a type provider could marry any arbitrary (trait-signature, class) pair for you.  Actually, a tagged (attributed) [<Trait>] interface might meet the basic template need better.

Is it just data that you want, or access to methods too?

Isaac Abraham

unread,
Mar 26, 2015, 5:39:43 PM3/26/15
to fsharp-o...@googlegroups.com
Not really. It's not about the type resolution or inference mechanism. It's about allowing multiple types, which have no commonality, being able to share common code based on common fields on the record. I think this is about extending the F# type system to being part structural as well as mostly nominative as it is now.

From: Steven Taylor
Sent: ‎26/‎03/‎2015 18:06

Isaac Abraham

unread,
Mar 26, 2015, 5:44:03 PM3/26/15
to fsharp-o...@googlegroups.com
Errt just to clarify the somewhat contradictory sentence below - by "no commonality" I am referring to sharing a common base type or interface.

From: Isaac Abraham
Sent: ‎26/‎03/‎2015 22:39
To: fsharp-o...@googlegroups.com
Subject: RE: Theoretical feature for F# (discussion)

Daniel Fabian

unread,
Mar 27, 2015, 1:33:19 AM3/27/15
to fsharp-o...@googlegroups.com
Those inline traits, I think can be thought of, as something quite similar to go's interfaces.

Daniel Fabian

unread,
Mar 27, 2015, 10:21:18 AM3/27/15
to fsharp-o...@googlegroups.com

Actually, come to think of it… Maybe a less intrusive approach could be useful in practice…

How about we’d add either an implicit (or probably more likely) keyword to create a wrapper interface;

type IDuck =
    abstract member Quack : unit -> string
    abstract member Fly : unit -> unit

let bird1 = MyDuckNotImplementingIDuck()

let fly (duck:IDuck) =
    duck.Fly()

let quack (duck:IDuck) =
    duck.Quack()

// new F# feature
fly bird1 // implicit wrapper like { new IDuck with member Fly () = bird1.Fly(); Quack () = bird1.Quack() }

// more explicit syntax
fly (adopt bird1)

in both cases, though, the F# compiler can do the necessary compatibility checks on the call-site.

Steven Taylor

unread,
Mar 28, 2015, 7:12:36 AM3/28/15
to fsharp-o...@googlegroups.com
Got that.  Why can't that be in a type provider as a first step in the path?

Sent from my iPod

Steven Taylor

unread,
Mar 28, 2015, 7:44:00 AM3/28/15
to Steven Taylor, fsharp-o...@googlegroups.com
As in, you dot into an instantiated il gen interface.  You could extend with that approach now. Probably better to focus on other rough edges first when it comes to core features.

Ernesto Rodriguez

unread,
Mar 29, 2015, 4:41:29 AM3/29/15
to fsharp-o...@googlegroups.com, Steven Taylor
I agree that member constraints are a bit hard to use in F# and this feature seems appealing. However, I was considring wether the situation could be made better with some extensions of F# type synonyms. Namele allowing things (as in Haskell) such as:

type Number<'t> = 't when member add : int -> int

sum<'t when Number<'t>> (ts : 't list) = ...  // instead of writing sum<'t when 't : member Add : 't -> 't> (t::ts : 't list) = ...

Cheers,

Ernesto
Ernesto Rodriguez

Masters Student
Computer Science
Utrecht University



Message has been deleted

panesofglass

unread,
Apr 3, 2015, 10:53:48 AM4/3/15
to fsharp-o...@googlegroups.com
On Friday, March 27, 2015 at 9:21:18 AM UTC-5, Daniel Fabian wrote:

Actually, come to think of it… Maybe a less intrusive approach could be useful in practice…

How about we’d add either an implicit (or probably more likely) keyword to create a wrapper interface;

type IDuck =
    abstract member Quack : unit -> string
    abstract member Fly : unit -> unit

let bird1 = MyDuckNotImplementingIDuck()

let fly (duck:IDuck) =
    duck.Fly()

let quack (duck:IDuck) =
    duck.Quack()

// new F# feature
fly bird1 // implicit wrapper like { new IDuck with member Fly () = bird1.Fly(); Quack () = bird1.Quack() }

// more explicit syntax
fly (adopt bird1)

in both cases, though, the F# compiler can do the necessary compatibility checks on the call-site.

Daniel Fabian

unread,
Apr 3, 2015, 11:43:27 AM4/3/15
to fsharp-o...@googlegroups.com
Well, it depends on how one would implement them extension interfaces. If they were just adapters / wrappers, then sure, it goes in a similar direction. As soon, as you are talking of some way of actually retrofitting interfaces somehow with inheritance, it is slightly different, I think. The wrapper approach is fairly local and the type would be, similar to object expressions, just some random anonymous type. Whereas an inheritance-based approach would likely want to subclass your type in some way and would probably only work on non-sealed classes.

--
Reply all
Reply to author
Forward
0 new messages