Python from Wise Guy's Viewpoint

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stephen J. Bevan

    Re: Python from Wise Guy's Viewpoint

    Pascal Costanza <costanza@web.d e> writes:[color=blue]
    > Fergus Henderson wrote:
    >[color=green][color=darkred]
    > >> Dynamic typing works better with XP than static typing because with
    > >> dynamic typing you can write unit tests without having the need to
    > >> immediately write appropriate target code.[/color]
    > > That one seems to have been pretty thoroughly debunked by other
    > > responses
    > > in this thread. A static type system won't stop you writing unit tests.
    > > And if you want to actually run the unit tests, then you are going to
    > > need appropriate target code, regardless of whether the system is
    > > statically or dynamically typed.[/color]
    >
    > Not if I only want to check whether the first ten tests work, and
    > don't care about the remaining ones.[/color]

    Perhaps I'm just a low tech kind of guy but if I just want to run the
    first ten then I comment out the rest. Even without a fancy IDE that
    only take a few key presses.

    Comment

    • Matthew Danish

      Re: Python from Wise Guy's Viewpoint

      On Mon, Oct 27, 2003 at 10:08:15PM +0100, Joachim Durchholz wrote:[color=blue]
      > Matthew Danish wrote:
      >[color=green]
      > >On Mon, Oct 27, 2003 at 07:00:01PM +0100, Andreas Rossberg wrote:
      > >[color=darkred]
      > >>Pascal Costanza wrote:
      > >>
      > >>>Can you show me an example of a program that does't make sense anymore
      > >>>when you strip off the static type information?
      > >>
      > >>Here is a very trivial example, in SML:
      > >>
      > >> 20 * 30
      > >>
      > >>Multiplicatio n, as well as literals, are overloaded. Depending on
      > >>whether you type this expression as Int8.int (8-bit integers) or
      > >>IntInf.int (infinite precision integer) the result is either 600 or an
      > >>overflow exception.[/color]
      > >
      > >May I point out that the correct answer is 600, not overflow?[/color]
      >
      > No, the correct answer isn't 600 in all cases.
      > If it's infinite-precision arithmetic, the correct answer is indeed 600.
      > If it's 8-bit arithmetic with overflow, there is no correct answer.
      > If it's 8-bit arithmetic with wrap-around, the correct answer is 88.
      > If it's 8-bit arithmetic with saturation, the correct answer is 255.
      > (The result happens to be independent of whether the arithmetic is
      > signed or unsigned.)[/color]

      What is this stuff? I am talking about integers here! You know, the
      infinite set with the same cardinality as natural numbers. Why can't
      the implementation figure out how to represent them most efficiently?
      [color=blue]
      > Using infinite-precision internally for all calculations isn't always
      > practicable, and in some algorithms, this will give you even wrong
      > results (e.g. when multiplying or dividing using negative numbers, or
      > with saturating arithmetic).[/color]

      If it gives you the wrong results, I'm not interested. How hard is it
      to get the arithmetically correct result of 20 * 30? Surely 20 * -30 is
      not that difficult either. It is a pet peeve I have with many
      programming languages, especially the ones that are so big on proofs and
      correctness.

      Arithmetic as it exists in ML is a good example of the difference
      between correctness and type-safety. It is also a good example of the
      difference between correctness and proof.

      Of course, you may claim, that the definition of div, or / or whatever
      it is called, is "correct" in that it conforms to the specification.
      All that says to me is that the specification is wrong. Garbage can be
      proven, in some system. Doesn't mean I'm interested.
      [color=blue]
      > Of course, this doesn't say much about the distinction between static
      > and dynamic typing, actually the issues and unlucky fringe cases seem
      > very similar to me. (In particular, overloading and type inference don't
      > tell us whether the multiplication should be done in 8-bit, 16-bit,
      > machine-precision, infinite-precision, wrap-around, or saturated
      > arithmetic, and run-time types don't give us any useful answer either.)[/color]

      Lisp gets exact rational arithmetic right, why don't ML or Haskell?
      Clever compilers like CMUCL can even emit efficient code when it can
      figure out the specific types. Surely a statically typed language would
      find this even easier!

      --
      ; Matthew Danish <mdanish@andrew .cmu.edu>
      ; OpenPGP public key: C24B6010 on keyring.debian. org
      ; Signed or encrypted mail welcome.
      ; "There is no dark side of the moon really; matter of fact, it's all dark."

      Comment

      • Marcin 'Qrczak' Kowalczyk

        Re: Python from Wise Guy's Viewpoint

        On Tue, 28 Oct 2003 02:46:54 +0100, Pascal Costanza wrote:
        [color=blue]
        > Sorry, I don't get this. Why should it be more dangerous with dynamic
        > typing? Common Lisp definitely gets this right, and most probably some
        > other dynamically typed languages.[/color]

        Common Lisp, Scheme and Perl get it right: the result of / on integers
        is a rational or floating point number, and integer division is spelled
        differently.

        Python and Ruby get it wrong: the result is an integer (truncated
        division), very different from the result of / on the same numbers
        represented in a different type.

        If a statically typed language get's this "wrong", it doesn't hurt, except
        newbies which write 1/n. For example consider this:

        double foo(double *a, int len)
        {
        ... Some computation involving a[i]/a[j] which is supposed
        ... to produce a true real quotient.
        }

        You make some array of doubles, set a[i] = exp(i) (a double) and it works.
        Then you set a[i] = 2*i (an integer) and it still works, because the
        integer has been converted to double during assignment. An integer can be
        used in place of a double with the same value.

        Now in a dynamically typed language the analogous code would set some
        array elements to integers without conversion. If division on them means
        a different thing, an integer can no longer be used in place of a floating
        point number with the same value. And division is the only operation whith
        breaks this.

        Dynamically typed languages shouldn't use / for both real and truncating
        division. For statically typed languages it's only a matter of taste (I
        prefer to use different symbols), but for dynamically typed languages it's
        important to prevent bugs.

        --
        __("< Marcin Kowalczyk
        \__/ qrczak@knm.org. pl
        ^^ http://qrnik.knm.org.pl/~qrczak/

        Comment

        • ketil+news@ii.uib.no

          Re: Python from Wise Guy's Viewpoint

          Matthew Danish <mdanish@andrew .cmu.edu> writes:
          [color=blue]
          > On Mon, Oct 27, 2003 at 10:08:15PM +0100, Joachim Durchholz wrote:[color=green]
          >> Matthew Danish wrote:[/color][/color]
          [color=blue][color=green][color=darkred]
          >>>On Mon, Oct 27, 2003 at 07:00:01PM +0100, Andreas Rossberg wrote:[/color][/color][/color]
          [color=blue][color=green][color=darkred]
          >>>>Pascal Costanza wrote:[/color][/color][/color]
          [color=blue][color=green][color=darkred]
          >>>>> Can you show me an example of a program that does't make sense anymore
          >>>>> when you strip off the static type information?[/color][/color][/color]
          [color=blue][color=green][color=darkred]
          >>>> Here is a very trivial example, in SML:
          >>>>
          >>>> 20 * 30[/color][/color][/color]
          [color=blue][color=green]
          >> No, the correct answer isn't 600 in all cases.[/color][/color]
          [color=blue]
          > What is this stuff? I am talking about integers here![/color]

          But the SML program isn't. Or it may be, and maybe not. So it's
          ambigous without type information.
          [color=blue]
          > Why can't the implementation figure out how to represent them most
          > efficiently?[/color]

          Because it needs a type annotation or inference to decide that the
          numbers are indeed integers, and not a different set with different
          arithmetic properties.
          [color=blue]
          > Lisp gets exact rational arithmetic right, why don't ML or Haskell?[/color]

          Could you point to a case where they don't? I don't understand your
          criticism at all. Is the ability to do modulo arithmetic "wrong"?

          -kzm
          --
          If I haven't seen further, it is by standing in the footprints of giants

          Comment

          • Matthew Danish

            Re: Python from Wise Guy's Viewpoint

            On Tue, Oct 28, 2003 at 11:20:45AM +0100, ketil+news@ii.u ib.no wrote:[color=blue]
            > Matthew Danish <mdanish@andrew .cmu.edu> writes:[color=green]
            > > What is this stuff? I am talking about integers here![/color]
            >
            > But the SML program isn't. Or it may be, and maybe not. So it's
            > ambigous without type information.
            >[color=green]
            > > Why can't the implementation figure out how to represent them most
            > > efficiently?[/color]
            >
            > Because it needs a type annotation or inference to decide that the
            > numbers are indeed integers, and not a different set with different
            > arithmetic properties.[/color]

            1 is an integer. Simple type inference. In Lisp, it's also a fixnum,
            it's also an (unsigned-byte 23), it's also an (integer 1 (2)), etc.
            [color=blue][color=green]
            > > Lisp gets exact rational arithmetic right, why don't ML or Haskell?[/color]
            >
            > Could you point to a case where they don't? I don't understand your
            > criticism at all. Is the ability to do modulo arithmetic "wrong"?[/color]

            - fun fact 0 = 1 | fact n = n * fact (n - 1);
            val fact = fn : int -> int
            - fact 10;
            val it = 3628800 : int
            - fact 15;
            val it = 1307674368000 : int (* ideally *)

            - 1 * 1.0;
            val it = 1.0 : float (* ideally *)

            - 2 / 4;
            val it = 1/2 : ratio (* ideally *)

            - 2 truncate 4;
            val it = 0 : int

            --
            ; Matthew Danish <mdanish@andrew .cmu.edu>
            ; OpenPGP public key: C24B6010 on keyring.debian. org
            ; Signed or encrypted mail welcome.
            ; "There is no dark side of the moon really; matter of fact, it's all dark."

            Comment

            • Andreas Rossberg

              Re: Python from Wise Guy's Viewpoint

              prunesquallor@c omcast.net wrote:[color=blue]
              >
              > I offered my `black hole' program and got these responses:
              >
              > Remi Vanicat <vanicat+invali d@labri.fr>
              > `I don't see how this function can be useful...'
              >
              > Jesse Tov <tov@eecs.harvR EMOVEard.edu>
              > `we don't need functions with those types.'
              >
              > Dirk Thierbach <dthierbach@gmx .de>
              > `recursive types are very often a result of a real typing error.'
              >
              > "Marshall Spight" <mspight@dnai.c om>
              > `I don't believe the feature this function illustrates could be
              > useful.'
              >
              > Will this the response for any program that does, in fact, fool a
              > number of static type checkers?[/color]

              You missed one important point here. It is, in fact, trivial to extend
              Hindley-Milner type inference in such a way that it can deal with your
              function. That's what OCaml does when given the -rectypes option.
              However, it is a conscious, deliberate decision not to do so, at least
              not by default!

              Why is that? Well, Dirk's quote gives the reason. But let me elaborate.

              The design of a type system is by no means canonical. In fact, it is
              based on set of pragmatic decisions and trade-offs. Idealized, you start
              with the trivial type system, which has only one type. Then you refine
              it incrementally by distinguishing certain classes of values through
              introduction of new types and typing rules. Introduction of typing rules
              is based on the following criteria:

              - Do they catch a lot of errors?
              - Are these errors serious?
              - Are they hard to localize otherwise?
              - Does the refinement rule out useful constructions?
              - Are such constructions common?
              - Are they expressible by other means?
              - Are the rules intuitive?
              - Do they interact nicely with other rules?

              And probably more. There are never any definite answers to any of these
              questions. The trade-off depends on many factors, such as the problem
              domain the language is used for. Usually the line is drawn based on
              experience with other languages and known problem domains. In the case
              of arbitrary recursive types, experience with languages that allowed
              them has clearly shown that it caused much more grief than joy.

              BTW, almost the same criteria as above apply when you as a programmer
              use the type system as a tool and program it by introducing your own
              types. It can be tremendously useful if you make the right strategic
              decisions. OTOH, especially if you are unexperienced, type abstractions
              might also turn out to be counterproducti ve.

              - Andreas

              --
              Andreas Rossberg, rossberg@ps.uni-sb.de

              "Computer games don't affect kids; I mean if Pac Man affected us
              as kids, we would all be running around in darkened rooms, munching
              magic pills, and listening to repetitive electronic music."
              - Kristian Wilson, Nintendo Inc.

              Comment

              • ketil+news@ii.uib.no

                Re: Python from Wise Guy's Viewpoint

                Matthew Danish <mdanish@andrew .cmu.edu> writes:
                [color=blue]
                > 1 is an integer. Simple type inference.[/color]

                Okay, I'm not familiar enough with ML, and I didn't know that it won't
                let you use 1 to represent 1.0 or 1/1 or whatever.
                [color=blue][color=green][color=darkred]
                >>> Lisp gets exact rational arithmetic right, why don't ML or Haskell?[/color][/color][/color]
                [color=blue][color=green]
                >> Could you point to a case where they don't? I don't understand your
                >> criticism at all. Is the ability to do modulo arithmetic "wrong"?[/color][/color]
                [color=blue]
                > - fun fact 0 = 1 | fact n = n * fact (n - 1);
                > val fact = fn : int -> int
                > - fact 10;
                > val it = 3628800 : int
                > - fact 15;
                > val it = 1307674368000 : int (* ideally *)[/color]

                Here's Haskell as provided by GHCi:

                Prelude> let fact n = if n == 0 then 1 else n * fact (n-1)
                Prelude> fact 10
                3628800
                Prelude> :i it
                -- it is a variable
                it :: Integer
                Prelude> fact 15
                1307674368000

                So '10' defaults to Integer, which is infinite precision.
                You can of course also do:

                Prelude> fact 10.0
                3628800.0
                [color=blue]
                > - 1 * 1.0;
                > val it = 1.0 : float (* ideally *)[/color]

                Prelude> 1*1.0
                1.0

                The 1 is treated as a Float, since that is what * requires
                [color=blue]
                > - 2 / 4;
                > val it = 1/2 : ratio (* ideally *)[/color]

                Prelude> 2/4
                0.5
                Prelude> (2/4 :: Rational)
                1 % 2

                The default is Float, but Rational is there if that's what you want
                [color=blue]
                > - 2 truncate 4;
                > val it = 0 : int[/color]

                I assume this means:

                Prelude> 2 `div` 4
                0
                Prelude> :i it
                -- it is a variable
                it :: Integer

                If I understood you correctly, Haskell doesn't get it all that wrong?

                -kzm
                --
                If I haven't seen further, it is by standing in the footprints of giants

                Comment

                • Tomasz Zielonka

                  Re: Python from Wise Guy's Viewpoint

                  prunesquallor@c omcast.net wrote:[color=blue]
                  >
                  > I offered my `black hole' program and got these responses:[/color]

                  It can be written in Haskell using laziness. Am I quite sure you will
                  object in some way ;)

                  blackHole :: a
                  blackHole = error "black-hole"

                  *BH> :t blackHole 1 2 3 'a' "ho" (blackHole, 1.2)
                  blackHole 1 2 3 'a' "ho" (blackHole, 1.2) :: forall t. t

                  *BH> blackHole 1 2 3 'a' "ho" (blackHole, 1.2)
                  *** Exception: black-hole

                  *BH> let _ = blackHole 1 2 3 'a' "ho" (blackHole, 1.2) in "abcdef"
                  "abcdef"

                  Best regards,
                  Tom

                  --
                  ..signature: Too many levels of symbolic links

                  Comment

                  • Andreas Rossberg

                    Re: Python from Wise Guy's Viewpoint

                    Matthew Danish wrote:[color=blue][color=green]
                    >>
                    >>Here is a very trivial example, in SML:
                    >>
                    >> 20 * 30
                    >>
                    >>Multiplicatio n, as well as literals, are overloaded. Depending on
                    >>whether you type this expression as Int8.int (8-bit integers) or
                    >>IntInf.int (infinite precision integer) the result is either 600 or an
                    >>overflow exception.[/color]
                    >
                    > May I point out that the correct answer is 600, not overflow?[/color]

                    No, it's not. If I choose type Int8 then I do so precisely for the
                    reason that I want to be signalled if some computation overflows the
                    intended value domain. Otherwise I had chosen IntInf or something. You
                    see, this is exactly the reason why I say that the type system gives you
                    expressiveness.
                    [color=blue]
                    > Something that annoys me about many statically-typed languages is the
                    > insistence that arithmetic operations should return the same type as the
                    > operands.[/color]

                    I should note in this context is that static types usually express
                    different things than dynamic ones, especially when it comes to number
                    types. In Lisp, the runtime tag of a number will usually describe the
                    representation of the number. This may well change between operations.
                    But static typing, at least in high-level languages, is about semantics.
                    If I choose a certain integer type I do so because it has the desired
                    domain, which I want to have checked - I'm not at all interested in its
                    representation. In fact, values of IntInf are likely to have multiple
                    representations depending on their size, but the type is invariant,
                    abstracting away from such low-level representation details.

                    Actually, I think dynamic typing should abstract from this as well, but
                    unfortunately this does not seem to happen.
                    [color=blue]
                    > 2 / 4 is 1/2, not 0.[/color]

                    Integer division is not real division (and should not use the same name).
                    [color=blue]
                    > Arithmetically, 1 * 1.0 is
                    > well-defined, so why can I not write this in an SML program?[/color]

                    Because the designers decided (rightly so, IMHO) that it is best to
                    avoid implicit conversions, since they might introduce subtle bugs and
                    does not coexist well with type inference. But anyway, this has nothing
                    to do with static vs dynamic typing - C allows the above, and there
                    might well be dynamic languages that raise a runtime error if you try it.
                    [color=blue]
                    > I do believe Haskell does it right, though, with its numeric tower
                    > derived from Lisp.[/color]

                    Yes, in Haskell you can write the above, but for slightly different
                    reasons (integer literals are overloaded for floating types).

                    - Andreas

                    --
                    Andreas Rossberg, rossberg@ps.uni-sb.de

                    "Computer games don't affect kids; I mean if Pac Man affected us
                    as kids, we would all be running around in darkened rooms, munching
                    magic pills, and listening to repetitive electronic music."
                    - Kristian Wilson, Nintendo Inc.

                    Comment

                    • Matthew Danish

                      Re: Python from Wise Guy's Viewpoint

                      You are right about Haskell, as I wrote in my initial post on this, it
                      has a numeric tower derived from Lisp (though I think it is not enabled
                      by default, or something?). Mostly I was annoyed that 20 * 30 being
                      possibly an overflow was brought up as an example of static typing being
                      expressive.

                      --
                      ; Matthew Danish <mdanish@andrew .cmu.edu>
                      ; OpenPGP public key: C24B6010 on keyring.debian. org
                      ; Signed or encrypted mail welcome.
                      ; "There is no dark side of the moon really; matter of fact, it's all dark."

                      Comment

                      • Joachim Durchholz

                        Re: Python from Wise Guy's Viewpoint

                        Matthew Danish wrote:
                        [color=blue]
                        > On Mon, Oct 27, 2003 at 10:08:15PM +0100, Joachim Durchholz wrote:
                        >[color=green]
                        >>Matthew Danish wrote:
                        >>[color=darkred]
                        >>>On Mon, Oct 27, 2003 at 07:00:01PM +0100, Andreas Rossberg wrote:
                        >>>
                        >>>>Pascal Costanza wrote:
                        >>>>
                        >>>>>Can you show me an example of a program that does't make sense anymore
                        >>>>>when you strip off the static type information?
                        >>>>
                        >>>>Here is a very trivial example, in SML:
                        >>>>
                        >>>> 20 * 30
                        >>>>
                        >>>>Multiplicat ion, as well as literals, are overloaded. Depending on
                        >>>>whether you type this expression as Int8.int (8-bit integers) or
                        >>>>IntInf.in t (infinite precision integer) the result is either 600 or an
                        >>>>overflow exception.
                        >>>
                        >>>May I point out that the correct answer is 600, not overflow?[/color]
                        >>
                        >>No, the correct answer isn't 600 in all cases.
                        >>If it's infinite-precision arithmetic, the correct answer is indeed 600.
                        >>If it's 8-bit arithmetic with overflow, there is no correct answer.
                        >>If it's 8-bit arithmetic with wrap-around, the correct answer is 88.
                        >>If it's 8-bit arithmetic with saturation, the correct answer is 255.
                        >>(The result happens to be independent of whether the arithmetic is
                        >>signed or unsigned.)[/color]
                        >
                        > What is this stuff? I am talking about integers here! You know, the
                        > infinite set with the same cardinality as natural numbers. Why can't
                        > the implementation figure out how to represent them most efficiently?[/color]

                        Hey, that 20*30 expression given above didn't say what type of integer
                        arithmetic was meant, or did it?
                        [color=blue][color=green]
                        >>Of course, this doesn't say much about the distinction between static
                        >>and dynamic typing, actually the issues and unlucky fringe cases seem
                        >>very similar to me. (In particular, overloading and type inference don't
                        >>tell us whether the multiplication should be done in 8-bit, 16-bit,
                        >>machine-precision, infinite-precision, wrap-around, or saturated
                        >>arithmetic, and run-time types don't give us any useful answer either.)[/color]
                        >
                        > Lisp gets exact rational arithmetic right, why don't ML or Haskell?[/color]

                        They do as well - infinite-precision integers are standard issue in
                        these languages.

                        It's just that Andreas's answer to the challenge of presenting a
                        type-dependent expression was simpler than anybody would have expected.
                        Of course, if your best response is that this all is ill-defined when it
                        isn't - then, I fear, you'll simply have to stay on your side of the fence.

                        Regards,
                        Jo

                        Comment

                        • Andreas Rossberg

                          Re: Python from Wise Guy's Viewpoint

                          prunesquallor@c omcast.net wrote:[color=blue]
                          > "Marshall Spight" <mspight@dnai.c om> writes:
                          >[color=green]
                          >>It would be really interesting to see a small but useful example
                          >>of a program that will not pass a statically typed language.
                          >>It seems to me that how easy it is to generate such programs
                          >>will be an interesting metric.[/color]
                          >
                          > Would this count?
                          >
                          > (defun noisy-apply (f arglist)
                          > (format t "I am now about to apply ~s to ~s" f arglist)
                          > (apply f arglist))[/color]

                          Moscow ML version 2.00 (June 2000)
                          Enter `quit();' to quit.
                          - fun noisyApply f x =
                          (print "I am about to apply "; printVal f;
                          print " to "; printVal x; print "\n";
                          f x);[color=blue]
                          > val ('a, 'b) noisyApply = fn : ('a -> 'b) -> 'a -> 'b[/color]
                          - noisyApply Math.sin Math.pi;
                          I am about to apply fn to 3.14159265359[color=blue]
                          > val it = 1.22460635382E~ 16 : real[/color]


                          In this example, printVal requires some runtime type information. But
                          that does in no way preclude static type checking.

                          --
                          Andreas Rossberg, rossberg@ps.uni-sb.de

                          "Computer games don't affect kids; I mean if Pac Man affected us
                          as kids, we would all be running around in darkened rooms, munching
                          magic pills, and listening to repetitive electronic music."
                          - Kristian Wilson, Nintendo Inc.

                          Comment

                          • Andreas Rossberg

                            Re: Python from Wise Guy's Viewpoint

                            Pascal Costanza wrote:[color=blue]
                            >[color=green]
                            >> As an example of the kind of "overloadin g" (or type dispatch, if you
                            >> want)
                            >> you cannot express in dynamically typed lagnuages: in Haskell, you can
                            >> naturally define functions which are overloaded on their return type,
                            >> i.e.
                            >> you don't need any value at all at runtime to do the "dispatch". For
                            >> example, consider an overloaded function fromString, that produces
                            >> values of
                            >> potentially arbitrary types from strings.[/color]
                            >
                            > Wrong.[/color]

                            Not sure how the "wrong" relates to the quoted paragraph, but I guess
                            you mean my conjecture that you cannot dispatch on return types with
                            dynamic typing.
                            [color=blue]
                            > (defmethod from-string-expansion (to-type string)
                            > (if (or (subtypep to-type 'sequence)
                            > (subtypep to-type 'character)
                            > (eq to-type t))
                            > `(coerce ,string ',to-type)
                            > `(coerce (read-from-string ,string) ',to-type)))
                            >
                            > (defmacro set-from-string (x string &environment env)
                            > (multiple-value-bind
                            > (bound localp declarations)
                            > (variable-information x env)
                            > (declare (ignore bound localp))
                            > (let ((type (or (cdr (assoc 'type declarations)) t)))
                            > `(setf ,x ,(from-string-expansion type string)))))[/color]

                            Interesting example, thanks for showing it. I'm not fluent enough in
                            Lisp to understand how this actually works but it does not seem to be
                            extensible in a compositional way (you have to insert all type cases by
                            hand). And does the resolution work transitively? I.e. if I write some
                            complex function f using fromString somewhere, performing arbitrary
                            calculations on its return value of type t, and returning something of a
                            type containing t, is all this code parametric in t such that I can call
                            f expecting arbitrary result types? All this would be automatic in Haskell.

                            Also note that your transcript shows that your approach indeed requires
                            *explicit* type annotations, while you would rarely need them when doing
                            the same thing in a language like Haskell.

                            Anyway, your code is complicated enough to make my point that the static
                            type system gives you similar expressiveness with less fuss.

                            - Andreas

                            --
                            Andreas Rossberg, rossberg@ps.uni-sb.de

                            "Computer games don't affect kids; I mean if Pac Man affected us
                            as kids, we would all be running around in darkened rooms, munching
                            magic pills, and listening to repetitive electronic music."
                            - Kristian Wilson, Nintendo Inc.

                            Comment

                            • Pascal Costanza

                              Re: Python from Wise Guy's Viewpoint

                              Andreas Rossberg wrote:[color=blue]
                              > Pascal Costanza wrote:
                              >[color=green]
                              >>[color=darkred]
                              >>> As an example of the kind of "overloadin g" (or type dispatch, if you
                              >>> want)
                              >>> you cannot express in dynamically typed lagnuages: in Haskell, you can
                              >>> naturally define functions which are overloaded on their return type,
                              >>> i.e.
                              >>> you don't need any value at all at runtime to do the "dispatch". For
                              >>> example, consider an overloaded function fromString, that produces
                              >>> values of
                              >>> potentially arbitrary types from strings.[/color]
                              >>
                              >>
                              >> Wrong.[/color]
                              >
                              >
                              > Not sure how the "wrong" relates to the quoted paragraph, but I guess
                              > you mean my conjecture that you cannot dispatch on return types with
                              > dynamic typing.
                              >[color=green]
                              >> (defmethod from-string-expansion (to-type string)
                              >> (if (or (subtypep to-type 'sequence)
                              >> (subtypep to-type 'character)
                              >> (eq to-type t))
                              >> `(coerce ,string ',to-type)
                              >> `(coerce (read-from-string ,string) ',to-type)))
                              >>
                              >> (defmacro set-from-string (x string &environment env)
                              >> (multiple-value-bind
                              >> (bound localp declarations)
                              >> (variable-information x env)
                              >> (declare (ignore bound localp))
                              >> (let ((type (or (cdr (assoc 'type declarations)) t)))
                              >> `(setf ,x ,(from-string-expansion type string)))))[/color]
                              >
                              >
                              > Interesting example, thanks for showing it. I'm not fluent enough in
                              > Lisp to understand how this actually works but it does not seem to be
                              > extensible in a compositional way (you have to insert all type cases by
                              > hand).[/color]

                              No, at least not in the default method for from-string-expansion I have
                              shown above. That method only covers the default cases, and needs to
                              distinguish different ways how Common Lisp handles pre-defined types.

                              What you would need to do for your own types is to write your own
                              specialized versions of from-string-expansion:

                              (defmethod from-string-expansion ((to-type (eql 'foo)) string)
                              `(somehow-convert-string-to-foo ,string))

                              You don't need to modify the method given above. (You need to write
                              conversion routines for your own types in any language.)
                              [color=blue]
                              > And does the resolution work transitively? I.e. if I write some
                              > complex function f using fromString somewhere, performing arbitrary
                              > calculations on its return value of type t, and returning something of a
                              > type containing t, is all this code parametric in t such that I can call
                              > f expecting arbitrary result types? All this would be automatic in Haskell.[/color]

                              It should be possible in principle. The macro shown above is expanded at
                              compile-time (this is 100% correct, but sufficiently correct for the
                              sake of our discussion). The &environment keyword captures the lexical
                              environment that is current at macro expansion time.
                              VARIABLE-INFORMATION looks up type information about a variable in that
                              environment, before the code is actually translated into its final form.

                              The original idea for such environment objects was that you could not
                              only look up standardized information about entities of the compilation
                              environment, but that you can also stuff in your own information. So in
                              principle, it should be possible to use this as a basis for a type
                              inferencing mechanism.

                              The downside of all this is that ANSI Common Lisp doesn't define the
                              needed functions to do all this. It defines such environment objects
                              only in very rudimentary ways that are actually not powerful enough.
                              CLtL2 had this stuff, but apparently it had some glitches that are hard
                              to get right, and it was decided to leave this stuff out of the ANSI
                              standard.

                              There are Common Lisp implementations that implement this functionality
                              to a certain degree, and apparently Duane Rettig of Franz Inc. is
                              currently working on an implementation that has sorted out the edge
                              cases. They seem to consider making this available as open source.

                              It's probably possible to do similar things with the ANSI-defined
                              DEFINE-COMPILER-MACRO, or with proprietary extensions like DEFTRANSFORM
                              in LispWorks.
                              [color=blue]
                              > Also note that your transcript shows that your approach indeed requires
                              > *explicit* type annotations, while you would rarely need them when doing
                              > the same thing in a language like Haskell.[/color]

                              I think it should be possible in principle to add type inferencing to
                              Common Lisp as a sophisticated macro package, even without proper
                              environment objects.

                              It would probably take serious effort to implement such a beast, and it
                              would be difficult to solve interferences with "third-party" Lisp code,
                              but at least you would not need to change the base compiler to add this.
                              [color=blue]
                              > Anyway, your code is complicated enough to make my point that the static
                              > type system gives you similar expressiveness with less fuss.[/color]

                              Yes, you're right. If you would want/need static type checking by
                              default, it wouldn't make much sense to do this in a dynamically typed
                              language that treats static type checking as an exceptional case. And
                              vice versa.


                              Pascal

                              --
                              Pascal Costanza University of Bonn
                              mailto:costanza @web.de Institute of Computer Science III
                              http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

                              Comment

                              • Alexander Schmolck

                                Re: Python from Wise Guy's Viewpoint

                                Marcin 'Qrczak' Kowalczyk <qrczak@knm.org .pl> writes:
                                [color=blue]
                                > Python and Ruby get it wrong: the result is an integer (truncated
                                > division), very different from the result of / on the same numbers
                                > represented in a different type.[/color]

                                It's being fixed since python >= 2.2 (sort of):
                                [color=blue][color=green][color=darkred]
                                >>> from __future__ import division
                                >>> 1/3[/color][/color][/color]
                                0.3333333333333 3331[color=blue][color=green][color=darkred]
                                >>> 5//2[/color][/color][/color]
                                2

                                'as

                                Comment

                                Working...