If you are using VS, you can right click the file and say move up/move down. It's annoying, sure, but thus far I've not had much problem with it. Manually editing XML or feeding things into the command line are not my style, either. :)

By on 7/8/2009 2:14 PM ()

Ask a silly question, get a silly answer: C# and F# are different languages with different features. In other words, your assumption that a naive (and broken) line by line translation of C# code into F# should "just work" is absurd.

Here is a more idiomatic F# version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type TransactionItem = { name: string; id: int; is_processed: bool }

let item(name, id) = { name=name; id=id; is_processed=false }
let mock_processor item = { item with is_processed = true }

let print items =
	for x in items do
		printf "Name: %s\nID: %d\nIsProcessed: %b\n" x.name x.id x.is_processed
		do
		  let items = Seq.map item ["Juliet", 1; "Bob", 2; "Jack", 3 ]
		  printf "Before:\n"
		  print items
		  let items = Seq.map mock_processor items
		  printf "After:\n"
		  print items
	stdin.ReadLine()

Note that your original code is nothing more than an exercise in unnecessary object orientation.

By on 7/6/2008 7:00 PM ()

I don't want to go into my solution and edit the XML by hand just to get the files to pass to the compiler in the right order, and I don't want to type the commandline by hand either. ... Is there a way to make the F# compiler more like the C# compiler, so that its not not so tighly coupled to the order that files are passed to compiler?

Ask a silly question, get a silly answer: C# and F# are different languages with different features. In other words, your assumption that a naive (and broken) line by line translation of C# code into F# should "just work" is absurd.

I appreciate your improved version of my code, but I think you might have missed my point :)

I wasn't asking how to write my program using F# idioms more effectively. I was asking how to make a non-trivial application, consisting of 4 or 5 or more sourcecode files, compile without any manual effort on my part to pass the files to compiler in the right order.

By on 7/6/2008 8:23 PM ()

I appreciate your improved version of my code, but I think you might have missed my point :)

I wasn't asking how to write my program using F# idioms more effectively. I was asking how to make a non-trivial application, consisting of 4 or 5 or more sourcecode files, compile without any manual effort on my part to pass the files to compiler in the right order.

The C# approach of making everything implicitly mutually recursive undermines reliability. In contrast, F# goes to great lengths to improve reliability by encouraging programmers to couple definitions only when necessary, to make it explicit using "rec" and then the F# compiler will still emit a warning if the evaluation order might be undefined. Adding this safety to a language at the cost of having to structure your code properly is trade-off well worth taking.

The problem is really that the current Visual Studio mode does not provide adequate support. The IDE should either sort dependencies for you or it should at least let you drag and drop the files to sort them by hand.

Cheers,
Jon Harrop.

By on 7/7/2008 6:03 PM ()

"In contrast, F# goes to great lengths to improve reliability by encouraging programmers to couple definitions only when necessary, to make it explicit using "rec" and then the F# compiler will still emit a warning if the evaluation order might be undefined. "

Wait, how do you use rec for that?

I'm trying to inherit an EventArgs that'll hold a Server property. And then the Server itself raises an event that the EventArgs needs to use.

It's more of a matter of necessity than best practice in this case. I can't change how EventArgs works.

By on 7/6/2009 12:05 AM ()

First, briefly, much of this thread is very old; the VS UI now lets you sort file order, as described in the second half of this blog entry:

[link:lorgonblog.spaces.live.com]

reinux, for your question, it sounds like you need mutually recursive types, e.g.

1
2
3
type Server() = ...

and ServerEventArgs() = ...

where the "type ... and ..." allow two types to reference one another.

By on 7/6/2009 10:29 AM ()

Brian, the thread may be old, but the problem is still there...

Sure, F# is not C#, but both are now part of the same family.

If the IDE of C# and F# look similar, users expect them to behave similarly.

As the order of files is not relevant for any of the major languages supported by Visual Studio, it should not be relevant for F#, at least not when using Visual Studio.

The current solution lets users reorder files in the solution explorer using the context menu, but I find it painful.

1. Move the cursor to the file
2. Right click
3. Move the cursor to the arrow corresponding to the desired direction
4. Left click

Moving a file more than one step or moving a group files is very annoying. Drag-and-drop would work better.

By on 7/6/2009 11:17 AM ()

As the order of files is not relevant for any of the major languages supported by Visual Studio, it should not be relevant for F#, at least not when using Visual Studio.

While some consistency is important it is obviously also not desirable to simply replicate the existing .NET languages.

The current solution lets users reorder files in the solution explorer using the context menu, but I find it painful.

You don't have to use the context menu. You can simply click on a file and press ALT+UP or ALT+DOWN to move it. This and many other interesting factoids about F# development in VS 2008 were presented in the latest F#.NET Journal article.

By on 7/6/2009 11:40 AM ()

As the order of files is not relevant for any of the major languages supported by Visual Studio, it should not be relevant for F#, at least not when using Visual Studio.

While some consistency is important it is obviously also not desirable to simply replicate the existing .NET languages.

Then the GUI in Visual Studio should reflect the fact that F# differs from other languages. Could be as simple as adding a number in front of the file name in the list.

The current solution lets users reorder files in the solution explorer using the context menu, but I find it painful.

You don't have to use the context menu. You can simply click on a file and press ALT+UP or ALT+DOWN to move it. This and many other interesting factoids about F# development in VS 2008 were presented in the latest F#.NET Journal article.

Thanks for the tip! Still, there is problem here. Juliet didn't know about the context menu, and thought she would have to edit the XML by hand. I knew about the context menu, but not about the keyboard shortcut. Where is this information available, and can we expect users to find and read it?

By on 7/7/2009 3:25 AM ()

Where is this information available, and can we expect users to find and read it?

I find gems like this all over the web and collate them into F#.NET Journal articles.

Cheers,
Jon.

By on 7/8/2009 1:57 PM ()

I have always thought that a key motivator for this kind of linear ordering is due to one of many difficult design decisions in fitting a functional language like F# to .NET. Specifically, global type inference + nominal types + ad hoc polymorphism forces this result.

Basically, my guess is that global type inference like F# does, unique to the .NET platform, needs this linear ordering if its to work with the more complex types like classes which might have overloading and stuff.

Seeing as F# is targeted at the algorithmically and numerically intense folks who want to get in there and test out stuff this seems a very tiny annoyance of a compromise. Given a choice of spending 2 seconds extra thinking about your project or global type inference I know which I'd choose. Especially with how trivial it is to rearrange stuff now.

By on 7/8/2009 8:59 AM ()

Specifically, global type inference  + nominal types + ad hoc polymorphism forces this result.

That's what I thought too, but the fact that you can "and" type definitions together indicates otherwise.

Seeing as F# is targeted at the algorithmically and numerically intense folks who want to get in there and test out stuff this seems a very tiny annoyance of a compromise.

I thought F# was targeted at .NET developers who wanted the benefits of functional programming whilst not having to give up on the .NET library and its features or on publishing real .NET libraries. Otherwise OCaml and some native calls would have sufficed.

Given a choice of spending 2 seconds extra thinking about your project or global type inference I know which I'd choose. Especially with how trivial it is to rearrange stuff now.

I think that's fair to say when you're writing applications. But when you're writing libraries, your public types and their members constitute the UX.

If a Window has a collection of Controls and a Control has a reference to its parent window, and I had to downcast it from the proxy Window interface to the Window object every time I tried to access it from a control (or downcast from the Control proxy to the Control each time I iterated through the list of controls in a Window), for no better a reason than that the library was implemented in a version of F# that doesn't have a viable way of exposing cross-referenced objects, I'd be disappointed.

I think this sort of thing will become more and more noticeable (and annoying) as more people start writing libraries in F#.

Also, again, it doesn't seem as though global type inference is lost by making type definitions orderless.

By on 7/8/2009 12:13 PM ()

Specifically, global type inference + nominal types + ad hoc polymorphism forces this result.

That's what I thought too, but the fact that you can "and" type definitions together indicates otherwise.

I think you misunderstand me. I know you can get mutually recursion using and; but that is not what I meant. Alot of why F# is the way it is is due to its underlying type system. It uses a variation of the Hindley Milner type system. This choice is why things like the rec keyword and 'and' keyword happen. When doing type inference it needs to know which functions are mutually recursive so it does not over generalize on the inferred type. All functions are not automatically defined as mutually recursive which reduces coupling as well as other safety benefits.

On the framework heavy platforms like .net and jvm, languages which feature type inference tend to not use HM because it does not play well with so called OOP languages. Languages like Scala, C# , Vb.net , boo, nemerle cannot infer global types or mutually recursive types and if so, only in a very limited manner. F#, however decided to not make a half hearted attempt at type inference and so used HM type inference. However, as stated, because HM does not work as well when mutual recursion or anything which make it difficult to arrive at a correct typing things like inheritance, certain kind of classes, overloading etc do not play well with it.

I am sure the people had to do some hacks to get it to work. Its quite impressive that they did. It is not as robust as Haskell and Ocaml but whenever I think of how much more is involved in interoperating with a platform like .NET I am always inclined to be impressed than to frown. Anyways, F# types in a top down manner, gathering all the information it can so it can type those pesky overloaded inherited types. It will be very difficult to get a typing system that did not need to do this while being able to infer types within a reasonable timeframe and not have the solver hang (especially at the response rate required by the IDE). At least not yet I dont think.

Anyways before complaining you must know where F# is coming from. It has to make some practical sacrifices in both directions (functional and framework compliance) so that it can actually be usable in the real world.IMO they are well chosen too cause they end up not mattering much. It straddles two planes quite impressively, with one foot in academia and another in industry. I mostly write libraries in F# yet I have not faced your problem, it requires you to go differently about how you approach your problem. The whole class, inheritance based model is not gonna get you very far. You have to do a rethink on how you organize things, smaller loosely coupled to near independence based components meant to be composed. I do not use it for GUI or ASPX frontends because that is not where its strength is at. To be honest I do not think it does OOP well, Scala got that better. Even nemerle does i feel. But Scala is not as lean, succinct and to the point, requiring more redundant baggage to manipulate mentally. So while wining in the large, it loses out to F# by far in the core.

I hope that is clearer.

By on 7/9/2009 9:55 AM ()

Okay, I understand now that cross-references do in fact inhibit type inference. I also see that it isn't as great for GUIs, considering you can't directly bind to immutable objects and expect it to update, for obvious reasons. On the other hand, that's only certain features of the language that don't work well, albeit some of the most interesting ones. While F# is not as great at creating GUIs as it is at doing other things, there does not seem to me to be any inherent reason that F# is not as great as C# at creating GUIs.

Aside from the need to compile in an arbitrary order, are there any other reasons that F# is unsuitable for ASPX? Though I haven't read that section of Expert F# yet, it would seem to me to be otherwise quite useful for that.

While I understand that "and"ing together types results in some features and aesthetics being sacrificed, those are sacrifices that I would be paying for, not anyone else, so thus I would prefer to have the option to do so when need be. F# without perfect type inference would still result in less (and generally better) code than if I were to code in C#, especially when considering that I can still use type inference features to its fullest elsewhere.

There's a section in Don Syme's Expert F# written:

"Restrict the constructs you use in your public APIs to those that are most easily used and recognized by .NET programmers. This means avoiding the use of some F# idioms in the public API."

I don't expect to be able to make use of everything that F# has to offer; losing some type inference on several types (which I explicitly select) isn't going to hurt.

If F# was designed with the philosophy of enforcing constraints rather than encouraging them, I don't think it would have been a new language; clearly, it would not have been able to interoperate with .NET at all.

By on 7/9/2009 1:17 PM ()

If a Window has a collection of Controls and a Control has a reference to its parent window, and I had to downcast it from the proxy Window interface to the Window object every time I tried to access it from a control (or downcast from the Control proxy to the Control each time I iterated through the list of controls in a Window), for no better a reason than that the library was implemented in a version of F# that doesn't have a viable way of exposing cross-referenced objects, I'd be disappointed.

What is wrong with this:

1
2
3
4
type Window(controls: Control list) =
  member this.Controls = controls
and Control =
  abstract member Parent : Window
By on 7/8/2009 1:51 PM ()

That requires Window and Control to be in the same source file.

brianmcn mentioned that yes, until they add support for recursive definitions spanning multiple files, this would be the only real way to do it.

But if that's the case, then it certainly can't be the case that a positive side-effect of the enforced ordering is navigability of code.

By on 7/8/2009 8:19 PM ()

While some consistency is important it is obviously also not desirable to simply replicate the existing .NET languages.

I don't buy that. That sort of reasoning is far from pragmatic. F# is a tool first, art second. It's not a research project anymore.

This is proving to be a real problem for me; I realized that my Server object is the parent of a collection of User objects, and the User objects need to reference the Server objects. The Server code and the User code are quite long. I can't possibly have them in the same .fs file.

The code is to be scripted against using DLR languages. That means that even though I'm trying to keep my private code as functional as possible, the exposed code needs to be standard OOP.

By on 7/6/2009 8:06 PM ()

This is proving to be a real problem for me; I realized that my Server object is the parent of a collection of User objects, and the User objects need to reference the Server objects. The Server code and the User code are quite long. I can't possibly have them in the same .fs file.

With regards to pragmatics here:

  • You can put them all in the same .fs file (no one relishes files that are tens of thousands of lines long, but F# will handle it ok).
  • Depending on exactly what's going on, you may be able to break the recursion among these classes by introducing an interface, e.g. IServer, so that e.g. user objects only need to see IServer. (You might find such an architecture preferable for other reasons too.)
  • We have some long-term plans to extend F# so that 'recursive code' can span multiple files, but such a language feature is unlikely to make the VS2010 release.

Languages have strengths and weaknesses... A strength of F# is that the ordering rule forces you to 'level' your architecture and you wind up with code that you can always walk up to and read "from top to bottom" without encountering forward references (compare walking up to a large C# project and trying to decide 'where to start reading code' to understand the whole code base)... The corresponding weakness is that when authoring OO frameworks (that often have a great deal of mutual recursion among a number of classes) F# currently will force you to define the whole framework in one file in a large "type ... and ... and ..." group in a single file.

By on 7/6/2009 9:28 PM ()

At first I questioned the file ordering thing in the IDE too, see this thread about ocamldep:
[link:cs.hubfs.net]

But now I'm with Brian on this too.
F# projects are much easier to read and maintain because dependency order is made explicit, also cycles being made explicit with intermediate interfaces is much clearer and lead to better designs in general.

I hope they keep explicit file ordering and explicit cycles in F# like how it's done now.

By on 7/7/2009 12:20 AM ()

I think the Solution Explorer list can still be automatically sorted in order of dependency even if strict hierarchical dependency isn't enforced. And yes, I agree, that would be quite nice to see, even for C# projects. But that doesn't require that things be compiled in order.

And really, if you don't want mutual dependencies and you have no need for it, then by all means, you can maintain a hierarchy. I don't see how it would hurt to have the option to allow mutual dependencies between files. But it does hurt that it can't be done when it really needs to be done.

After all, F#'s selling point is, as the devs describe it, that it encourages a lot of good functional habits the way Haskell and Ocaml do, but that it doesn't enforce them the way Haskell or Ocaml do.

As for the workarounds, I don't think that the benefits of enforcing hierarchical dependencies outweigh the need to create junction interfaces or stick everything in a single file.

By on 7/7/2009 1:27 AM ()

The IServer solution works -- barely. The only reason I can get it to work in this case is that Server itself creates the Users, so I can pass the IServer to the User via the constructor and thus avoid tampering by external scripts. This won't always be the case.

Cramming everything into a single .fs file makes it difficult for multiple developers to maintain a project.

The value of many libraries depends on their usability, so these sorts of issues have implications which are not only aesthetic but also very much practical.

Another thread mentioned that this is an even bigger issue for ASP.NET projects. One of the responses mentioned that F# doesn't officially support ASP.NET yet, but Expert F# has a whole chapter devoted to the subject -- so you'd expect it to be doable without having to resort to bizarre hacks relying on undocumented behavior (that ASPX compiles in alphabetical order).

Would definitely like to see this one fixed soon.

By on 7/6/2009 11:37 PM ()

This and many other interesting factoids about F# development in VS 2008 were presented in the latest F#.NET Journal article.

Is the article available without subscription?

By on 7/6/2009 12:24 PM ()

Ahh nice.

I guess the only caveat (if you can call it that) is that you have to keep both of the types in the same source file.

Thanks.

By on 7/6/2009 10:59 AM ()

Currently, there is no way to compile your F# application without manually specifying the compilation order of files (and editing the project file if necessary). However I would almost certainly expect that this will be fixed in the product version of F# that is properly intergrated with Visual Studio - so hang in there.

For the time being, one mitigating factor is that you'll typically have fewer source files in your F# project than would in a Java or C# project.

By on 7/7/2008 8:10 AM ()

I find it quite annoying, having to define the order of how the modules are compiled by the F# compiler manually. It seems so last century. I've only just begun exploring F# myself a few weeks ago but as far as I know there's no way around it.

Side note: I also find it strange that one has to write the keyword rec in front of the definition of a recursive function. Isn't it quite obvious that when a function should be recursive and an unnecessary burden on the programmer?

Daniel

By on 7/7/2008 7:29 AM ()

Side note: I also find it strange that one has to write the keyword rec in front of the definition of a recursive function. Isn't it quite obvious that when a function should be recursive and an unnecessary burden on the programmer?

It's sometimes useful to hide a value and redefine it. When x is an optional argument, I often write this kind of code:

1
2
...
let x = defaultArg x 0

With the "rec" keyword, the meaning changes.

However, for toplevel definitions, I agree the "rec" keyword could be optional (since 2 toplevel definitions can't have the same name).

By on 7/7/2008 10:01 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper