Yes, sure, this works.

Use OverloadIDAttribute if neccessary. See [link:cs.hubfs.net].

don

By on 4/7/2007 1:15 PM ()

Yes - having multiple constructors works for me OK, but here's a follow-on question.

When I have multiple constructors, usually the constructors with more arguments do the same stuff as the simple constructor, but also do a bit extra. Can I reuse the simple constructors in the more complicated ones?

Here's a cheesy example (I know this is wrong on many levels, but I hope you know what I mean):

1
2
3
4
5
6
7
8
type foo =
  class
    val mutable _x : int
    new() = { _x = 0 }
    new(x) as this = { _x = 0 } then this.setx(x)
    member this.setx(x) = this._x <- x
    member this.print() = print_int this._x
  end

How can I avoid repeating myself in the second constructor new(x)? I can't just call this.new() or new foo().

By on 7/3/2007 9:24 PM ()

There was a bug in 1.9.1.8 that prevented constructor reuse. Here is what it looks like as of 1.9.2.7

1
2
3
4
5
6
 
type foo =
    val _x : int
    new() = new foo(0)
    new(x) = { _x = x } 
    member this.print() = print_int this._x

Or, when using implicit construction syntax:

1
2
3
type foo(x) =
    new() = new foo(0)
    member this.print() = print_int x

BTW 1.9.2.7 is currently in the hands of our web release team - we expect to have a couple of additional 1.9.2 stabilization releases, since we're putting this one out as a "preview" for the Microsoft Faculty Summit that's happening this weekend.

Cheers!
don

By on 7/14/2007 11:52 PM ()

My apologies for posting on an older thread, but as my question is in the same vein, I thought it best to append it to this conversation, as opposed to starting a whole new thread.

Don, you show chaining a constructor without parameters to one with parameters, but is it possible to go the other way? For example:

1
2
3
4
5
6
type foo =
    class
        val _x : int

        new() = { _x = 0 }
        new(otherVal) = { this(); someOtherInit() }

DC

By on 8/16/2007 11:23 AM ()

Sure you can go the other way, but it seems more logical go the way Don suggests, as otherwise what would you do with the extra parameters? But if you want to here's how you do it:

1
2
3
4
5
6
type foo = class
       val _x : int
       new() = { _x = 0 }
       new(otherVal : obj) = new foo() then
        printf "%A" otherVal
end

Any logic not directly related to field initialization should come after the the then keyword.

Cheers,
Rob

By on 8/16/2007 1:31 PM ()

Well, I would use this as an example of doing it this way:

In C#, I might do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Foo
{
    private int a;
    private double b;
    private string c;

    Foo()
    {
        a = 0;
        b = 10.5;
        c = "blerg.";
    }

    Foo(int otherA) : this()
    {
        a = otherA;
    }

    Foo(double otherB) : this()
    {
        b = otherB;
    }
}

Without being able to refer back to the parameterless constructor, I'd have to reinitialize two of the variables to the same value in all three constructors. Yeah, it's a ludicrously contrived example, but I know I've got classes that initialize a lot of things, and having to do that would be a real pain. If there's a better way to think about the problem, though, I'm open to suggestions.

DC

By on 8/16/2007 2:05 PM ()

Hi, you can write code like this in F# as well:

1
2
3
4
5
6
7
8
9
10
 
#light
type Foo = 
  val a : int
  val mutable b : int

  new() = { a=20; b=22; } 
  new(b) as x = new Foo() then
    x.b <- b
  member x.Sum = x.a + x.b  

There are however a few issues - first, since the second constructor is modifying a value of b, the field has to be marked as mutable (even though you don't mutate it after construction). The second problem with this code is that there is some bug in the compiler, so it doesn't compile correctly (I'll report that to the F# team).

Anyway, I strongly recommend using the constructor with the largest number of arguments as the primary - this has an advantage that you can use implicit constructor syntax, which is very compact:

1
2
3
4
5
6
7
8
9
10
 
#light
type Foo(a:int, b:int) = 
  // constructor logic
  let sum = a + b
  do printf "SUM: %d" sum

  // members
  new() = new Foo(20,22)
  member x.Sum = a + b  

Here, the Foo class has one parameterless constructor and a constructor with two arguments. The arguments to the "implicit constructor" are automatically made available in the class. You can also use do and let to implement additional constructor logic.

By on 8/17/2007 5:48 AM ()

Hi,

Thanks for the prompt answer. Actually, I was wondering how one could use constructor overloading with the new syntax, but it is apparently done by adding new(...)={...} to the

1
type foo() = class end 

syntax

I have (yet) another question on initialization : is it possible to access methods in initialization functions as in the following example (except that it would get rid of canCompute, and use member x.CanCompute = periods > 0 directly)

1
2
3
4
5
6
 type computable(periods) =
    class        
        let canCompute = periods > 0
        let _ = if canCompute then print_string "good!"
        member x.CanCompute = canCompute            
    end

Thanks a lot !

By on 4/7/2007 6:31 PM ()
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