Live data from Hacker News

The Rust Platform

aturon.github.io

121–130 of 256 posts

Re: The Rust Platform

#121
post #119

Earlier quoted context omitted.

> How are type families worse than fundeps? That's a pretty ridiculous assertion; the things you can do with fundeps are strictly fewer than the things you can do with type families. It's not about how much you can do (otherwise, just use a dynamic language, you can do everything, even shoot yourself in the foot!), it's about whether the result makes sense, and how much effort it takes to make sense of it. > You're d…

> otherwise, just use a dynamic language, you can do everything, even shoot yourself in the foot! Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow. > it's about whether the result makes sense Which they do. Perhaps you have some examples of when type families confused you or made you perform an error? > Type families as provided in Haskell are incompatible…

> Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow.

Um, aren't functional dependencies an add-on to multiparameter type classes? I don't see where the opposition is.

> Which they do. Perhaps you have some examples of when type families confused you or made you perform an error?

I already gave an example above. I defined two type instances that violate the principle of not doing evil: https://ncatlab.org/nlab/show/principle+of+equivalence

> TFs aren't dependent types. However, they are on the right track.

Dependent types are a good idea. The way Haskell attempts to approximate them is not. Parametricity is too good to give up. With the minor exception of reference cells (`IORef`, `STRef`, etc.), if two types are isomorphic, applying the same type constructor to them should yield isomorphic types.

You know what type families actually resemble? What C++ calls “traits”: ad-hoc specialized template classes containing type members.

> Fundeps are farther away from the right idea.

Functional dependencies are a consistent extension to type classes, which don't introduce a second source of ad-hoc polymorphism, unlike type families.

> Why is this a problem? It makes sense from a theoretical perspective (we don't associate multiple ordering properties with the things we call "the integers"),

What if I want to order them as Grey-coded numbers? In any case, the integers are far from the only type that can be given an order structure, and many types don't have a clear “bestest” order structure to be preferred over other possible ones.

> and it's very easy to use newtype wrappers to create new instances if needed.

Creating `newtype` wrappers is easy at the type level, but using them is super cumbersome at the term level.

> ML modules are flexible, but backwards from a theoretical perspective.

ML modules are plain System F-omega: http://www.mpi-sws.org/~rossberg/1ml/ . Where's the backwardness?

> Parametricity is something that should be embedded in the type system, not the module system.

It's type families, as done in Haskell, that violate parametricity! Standard ML has parametric polymorphism, uncompromised by questionable type system extensions.

> Interesting example. However, I doubt that the syntactic cost of using such a system is less than the syntactic cost of enforcing global instance uniqueness and using newtype wrappers.

I can't imagine it being more cumbersome than wrapping lots of terms in newtype wrappers just to satisfy the type class instance resolution system.

Re: The Rust Platform

#122
post #42

Earlier quoted context omitted.

And notably, C++11 actually moves in this direction, standardizing things like smart pointers [0][1]. It's a very smart move for Rust. Core or near-core library wars in the early days of adoption of a language leads to duplication of effort, and for those invested in seeing Rust gain a set of libraries to rival other languages, this is a great thing. [0] https://en.wikipedia.org/wiki/C%2B%2B11#C.2B.2B_standard_lib...…

Actually, C++'s STL is in a weird situation, compared to the standard library in other languages, because the STL is a spec, not an implementation. And there are as many implementations of the STL as there are compilers. This might arguably happen if there were multiple Rust compilers, though. Anyways, the result on the C++ STL is that in many cases, the same types have different performance characteristics on differ…

Nit: C++ Standard Library != STL

Re: The Rust Platform

#123
post #77
post #72

Earlier quoted context omitted.

> Empirically, languages that have large standard > libraries (e.g. Java, Python, Go) seem to do better than > their competitors. You seem to be overlooking the ultimate counterexample: C. :P

JS, too, right? Forget "large" standard library, there really isn't any standard library at all

You have these built-in objects like Math and String and Array. Are those not the standard library?

Re: The Rust Platform

#124
post #119

Earlier quoted context omitted.

> otherwise, just use a dynamic language, you can do everything, even shoot yourself in the foot! Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow. > it's about whether the result makes sense Which they do. Perhaps you have some examples of when type families confused you or made you perform an error? > Type families as provided in Haskell are incompatible…

> Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow. Um, aren't functional dependencies an add-on to multiparameter type classes? I don't see where the opposition is. > Which they do. Perhaps you have some examples of when type families confused you or made you perform an error? I already gave an example above. I defined two type instances that violate the…

>Um, aren't functional dependencies an add-on to multiparameter type classes?

You're right, I meant "type families".

> I defined two type instances that violate the principle of not doing evil:

We're not doing abstract category theory; we're writing computer programs (well, I am). Have you ever run into a problem with type families in that capacity?

>if two types are isomorphic, applying the same type constructor to them should yield isomorphic types.

Agreed, but there's a difference between type functions and type constructors. TFs are (a limited form of) type functions. Value-level constructors admit lots of nice properties that value-level functions do not, and I see no reason to be uncomfortable with this being reflected at the type level.

> What if I want to order them as Grey-coded numbers

Use a newtype wrapper. Even if a language allowed ad-hoc instances, I would consider it messy practice to apply some weird non-intuitive ordering like this without specifically making a new type for it.

> Creating `newtype` wrappers is easy at the type level, but using them is super cumbersome at the term level.

And using ML-style modules is easy at the term level, but cumbersome at the type level.

It's a tradeoff, and I suspect that newtypes are usually the cleaner/easier solution.

> ML modules are plain System F-omega

I hadn't seen the 1ML project. That's pretty cool.

> It's type families, as done in Haskell, that violate parametricity!

How so? I really don't understand your argument here, if you just take TFs to be a limited form of type function.

Re: The Rust Platform

#125
post #71

Earlier quoted context omitted.

Maybe a change in attitude? Stability can be a good thing. Go's standard library doesn't change that much, and that's a strength. How about: "std is where code goes when it's done". As is, really done. The API's won't need changing.

Go isn't immune to the problem either. See the `flag` package, which is something that new users are encouraged to avoid in favor of e.g. https://github.com/jessevdk/go-flags .

I am a Go programmer and I've never seen anyone anywhere encouraging people to use anything over the flag package. How did you get such impression?

Re: The Rust Platform

#126
post #124

Earlier quoted context omitted.

> Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow. Um, aren't functional dependencies an add-on to multiparameter type classes? I don't see where the opposition is. > Which they do. Perhaps you have some examples of when type families confused you or made you perform an error? I already gave an example above. I defined two type instances that violate the…

>Um, aren't functional dependencies an add-on to multiparameter type classes? You're right, I meant "type families". > I defined two type instances that violate the principle of not doing evil: We're not doing abstract category theory; we're writing computer programs (well, I am). Have you ever run into a problem with type families in that capacity ? >if two types are isomorphic, applying the same type constructor to…

> We're not doing abstract category theory; we're writing computer programs (well, I am). Have you ever run into a problem with type families in that capacity?

I like being able to reason about my programs. For that to be a smooth process, the language has to be mathematically civilized.

> Agreed, but there's a difference between type functions and type constructors. TFs are (a limited form of) type functions.

By “type families”, I meant both data families and type families. Case-analyzing types is the problem, see below.

> And using ML-style modules is easy at the term level, but cumbersome at the type level.

Actually, ML-style modules are also more convenient at the type level too! If I want to make a type constructor parameterized by 15 type arguments, rather than a normal type constructor in the core language, I make a ML-style functor parameterized by a structure containing 15 abstract type members.

> How so? I really don't understand your argument here, if you just take TFs to be a limited form of type function.

“In programming language theory, parametricity is an abstract uniformity property enjoyed by parametrically polymorphic functions, which captures the intuition that all instances of a polymorphic function act the same way.”

https://en.wikipedia.org/wiki/Parametricity

Re: The Rust Platform

#127
post #120
post #113

Earlier quoted context omitted.

The problem is that streams actually have very complicated semantics when they interact with the real world. What does it mean to traverse an effectful stream multiple times? Can you even do that? Data.Vector provides a very efficient stream implementation for vector operation fusion, but it's unsuitable for iterators/streams that interact with the real world. Pipes, on the other hand, combined with FreeT, provides g…

Just sticking with the pure types there's currently no generic stream model that works well. No stream fusion system fuses all cases (even in theory) and they also fail to fuse the cases they're supposed to handle too often in practice. I haven't looked at pipes, but I'm guessing it doesn't all fuse away either.

You're right, I believe Haskell's fusion framework could be greatly improved (although it is the best production solution I'm aware of). However, how would you go about solving this? I don't think there's any generalized solution to the problem of creating no-overhead iteration from higher-level iterative combinators.

Re: The Rust Platform

#128
post #39

I wouldn't recommend following the Haskell approach. It hasn't worked well for us. (I took part in creating the Haskell Platform and the process used to add packages to it. I also used to maintain a few of our core libraries, like our containers packages and networking). Small vs large standard library: A small standard library with most functionality in independent, community-maintained packages has given us API fri…

I don't think most of these are applicable to Rust. > - Conversions between our 5(!) string types are very common. > - Standard library I/O modules cannot use new, de-facto standard string types (i.e. `Text` and `ByteString`) defined outside it because of dependency cycle. We have one string type defined in std, and nobody is defining new ones (modulo special cases for legacy encodings which would not be worth pollut…

> We have one string type defined in std

The standard library also includes Path/PathBuf and OsStr/OsString. And third-party libraries also use [u8] for bytestrings.

It'd be nice to improve handling for user-supplied text where you can't assume UTF-8. For instance, git2-rs provides the contents of diffs as [u8], because it can't assume the diffed files use UTF-8. That led to this commit today: https://github.com/ogham/rust-ansi-term/pull/19/commits/a0da...

That felt like a lot of boilerplate to abstract between str and [u8]. Is there a better way to solve that problem?

(As much as I'd love to just say "use UTF-8", that would break on many git repositories, including git.git and linux.git.)

Re: The Rust Platform

#129
post #112
post #90

Earlier quoted context omitted.

Lua's lack of a stdlib is also a curse. I can't imagine how many incompatible versions of string.trim and OOP libraries are out there in the wild right now... Things have been getting better lately because of Luarocks but its still an uphill battle.

String trim is just: foo:gsub("%s*$", "") or foo:gsub("^%s*", "") The standard idiom for OOP in Lua is a one-liner: return setmetatable(self, mt) where mt.__index has all the methods. How you assign to mt.__index can vary across modules according to style, but that's a _purely_ asethetic issue. The mechanics are identical. Using a module to accomplish it creates a useless dependency. There are many criticisms one cou…

If you're reading a pile of string processing code, seeing

    s.rstrip()
helps make code self-documenting, compared to

    s:gsub("%s*$", "")
I don't want to argue for a massive standard library (for instance, I don't think Python should have shipped modules for dbm, bdb, sqlite, or XML-RPC), but simple string processing seems like a good thing to standardize.

Re: The Rust Platform

#130
post #118
post #87

Earlier quoted context omitted.

The 'std lib is where libraries go to die' was invented by Python. The libs are shallow, don't break backwards compat and provide a substandard experience. Things that continue to improve provide an out of tree alternative package name. Python codebases that are resilient don't use much of "core", arrow for time, requests for http, simplejson, etc. Using core is an antipattern that will get you stuck on a version of…

Just as a data point... I like and heavily use the core libs... And not once i used arrow, request or simplejson, while knowing them, because i didn't feel the needs

Then you most likely have various security or logic problems in your application unfortunately.
Post reply on HN