quernd804 has quit [Quit: Ping timeout (120 seconds)]
mro has joined #ocaml
quernd80 has joined #ocaml
YuGiOhJCJ has quit [Quit: YuGiOhJCJ]
trillion_exabyte has quit [Read error: Connection reset by peer]
trillion_exabyte has joined #ocaml
neiluj has joined #ocaml
euphores has quit [Quit: Leaving.]
<neiluj>
Hi! got a function that pattern matches on a string and calls function from a module with a certain module type A
<neiluj>
I'd like to keep the pattern matching but call functions from a module with a module type B disjoint from A (though sharing one function)
<neiluj>
(so not disjoint actually)
<neiluj>
how could it be done?
<neiluj>
oh ok found a way, nevermind
ocra8 has quit [Ping timeout: 260 seconds]
<discocaml>
<faldor20> Thanks for your detailed reply :)
<discocaml>
<faldor20> I think my main issue is that observationally they seem to cause bad comment behaviour. I'd say Ocaml codebases have the worst commenting out of any language I've used. It's markedly different from other languages. I do think the expectation of "I'll write a comment in the mli files and that'll do" is part of the cause.
<discocaml>
<faldor20>
<discocaml>
<faldor20> Mostly when I'm reading and modifing a function I want all the information about it in front of me.
<discocaml>
<faldor20>
<discocaml>
<faldor20> I'd liken always needing mli files to having to write an interface for every single class in an OO language. It'd just feel silly and clunky.
* mbuf
Reminder OCaml Twitch streaming on Sets and Hash Tables today, Monday, May 27, 2024 at 1430 GMT | 1530 CEST | 1900 IST https://www.twitch.tv/shakthimaan
waleee has quit [Ping timeout: 240 seconds]
sable has joined #ocaml
mro has quit [Remote host closed the connection]
<discocaml>
<barconstruction> I think that a good syntax tradeoff would be
<discocaml>
<barconstruction> - in-module annotations that allow you to mark a type as abstract, or a variable as public or private; this determines the sealing interface of the module (because the implementor side abstraction is not many to many, it is one to one)
<discocaml>
<barconstruction> - for hierarchically nested modules, the annotations only control the innermost interface (that the module exposes to its siblings) but you have to write an interface file to describe how it relates to its grandparents and cousins, so to speak
<discocaml>
<barconstruction> - client side interfaces (generic programming against functors) would still have to be written using signatures
<discocaml>
<barconstruction> If you really want to define one signature which is used to seal many different modules you can still do that. I guess I just don't see why it's so important to be able to reuse the same signature to seal many different modules (as opposed to checking that many different modules implement the signature)
sable has quit [Remote host closed the connection]
<dh`>
what's the difference between "reuse the same signature to seal many different modules" and "checking that many different modules implement the signature"?
<dh`>
meanwhile, commenting and documentation practices are a social problem
vb has quit [Ping timeout: 268 seconds]
<dh`>
it is certainly possible for language frobs to have an effect on commenting and documentation practices, but it's mostly a matter of attitude and expectations
vb has joined #ocaml
<dh`>
anyway, I continue to disagree, separate interfaces are a lot clearer when working with nontrivial codebases
<discocaml>
<limp.biskit> what's the point of marking a type, inline, as abstract?
<discocaml>
<limp.biskit> here's the definition, but you can't get to it!
<discocaml>
<limp.biskit> misses 50% of the point
<discocaml>
<hockletock> you can gatekeep creation of values instead of doing runtime checks every time a value is used if you need values to obey some invariant
deadmarshal_ has joined #ocaml
mbuf_ has joined #ocaml
mbuf has quit [Ping timeout: 252 seconds]
Tuplanolla has joined #ocaml
<discocaml>
<._null._> Did you mean the idea of a syntax like `abstract type t = <definition>`, as following from the discussion above on separate interfaces, or something different?
<dh`>
haskell's export syntax does manage to distinguish between "export this type" and "export this type and all its constructors"
<dh`>
but you can't hide a type completely
<discocaml>
<contextfreebeer> One thing that annoys me is that if you write ml files with no type information but want to export readable types in the mli, you will still need to include the aliases in the ml file anyway, that is so annoying
<discocaml>
<._null._> I do wonder why that restriction is in place, I can't see any reason for it
neiluj has quit [Quit: WeeChat 4.2.1]
mbuf_ has quit [Quit: Leaving]
<dh`>
there's a number of cases where you have to cutpaste from .mli to .ml
<dh`>
there's basically no reason for it, it's because the original design had interfaces being strict subsets of structures
<discocaml>
<Kali> many times i use `ocamlc -i` to automatically generate the mli file and then just search-and-replace where needed
<dh`>
because that way it's simple and easily understood and relatively easily shown to be sound
<dh`>
and this happened a long time ago when nobody really understood any of this modularity stuff well
<octachron>
There are many reason for it. The first one is that the mli file is the source of truth and can offer a completely different view than the implementation.
gzar has joined #ocaml
jabuxas has joined #ocaml
<discocaml>
<._null._> One way to phrase it is : why are empty modules not implementations of interfaces which can work without implementations?
<discocaml>
<._null._> Since the mli is the source of truth, why is it needed in the implementation of it's not used there?
<discocaml>
<._null._> Since the mli is the source of truth, why is "the truth" needed in the implementation if it's not used there?
<discocaml>
<octachron> The mli is not needed in the implementation until checking that the implementation is a subtype of the interface.
<discocaml>
<octachron> (And the empty module is not a subtype of a non-empty interface.)
<discocaml>
<limp.biskit> hence the 50%
<discocaml>
<limp.biskit> the benefit on actually separating the logic from the signature is still worth making an mli imo
<discocaml>
<._null._> Can the theory not work when [no type] is a subtype of [type definition] ?
<discocaml>
<lukstafi> One is sometimes driven to use polymorphic variants for the sole reason of the extra flexibility -- not that there's anything wrong with polymorphic variants, so I have no qualms. (1) You can often omit the type definition in the .ml file. (2) You can easily avoid being forced to provide a source module for inclusion in modules intended to share an interface (there might also be tricky ways to do that using `with type`).
<discocaml>
<lukstafi> One is sometimes driven to use polymorphic variants for the sole reason of the extra flexibility -- not that there's anything wrong with polymorphic variants, so I have no qualms. --(1) You can often omit the type definition in the .ml file.-- (Edit: not sure what I was thinking here, the literal interpretation doesn't make sense.) (2) You can easily avoid being forced to provide a source module for inclusion in modules intended to share an i
<discocaml>
<octachron> @._null._ , that's an interesting idea ... that could potentially work?
<dh`>
afaik, if you have a type in a module, it can appear in the interface in only one of three ways: (1) not at all, (2) as just "type" so it's abstract, or (3) in full
<dh`>
it definitely doesn't make sense to export only some constructors of a sum
<dh`>
you could in principle export a partial set of the fields of a record, but I don't think you want to from a language design standpoint
<dh`>
but what this means is that if you have a full type definition in an interface, there's no actual need to repeat it in the source module
<dh`>
it's done that way in ml because it's always been done that way, and it was done that way originally for the reasons I said above
<dh`>
the same goes for various other kinds of declarations that otherwise need to be pasted
trillion_exabyte has quit [Ping timeout: 255 seconds]
trillion_exabyte has joined #ocaml
<discocaml>
<._null._> You can't export a partial set of fields in a record because the full set defines the memory layout
<octachron>
dh`, no a type can also appear with different type arguments (because the layout of type equalities is different, because the interface and implementation are exposing different generative functors, module names) or the same type name can also appear multiple time in the implementation.
<octachron>
"It was always done like that" has little influence on this matter. Having a nice and simple theory and implementation for dependent types + abstraction is not that straightforward.
jabuxas_ has joined #ocaml
jabuxas has quit [Read error: Connection reset by peer]
<discocaml>
<._null._> > the amount of cutpaste from the interface file that's sometimes required is a problem, but it's a fixable problem (it's e.g. fixed in coq)
<discocaml>
<._null._> dh`: What do you mean with that ?
oriba has joined #ocaml
<discocaml>
<leviroth> masterbuilder: with the `:=` syntax you can write aliases in signatures without including them in the implementation, if I understand what you mean.
<dh`>
in coq you don't have to repeat stuff from interfaces in their modules
<dh`>
(certain things, anyway)
<discocaml>
<._null._> What can you? You have to repeat definitions from the interface to the implementation
<dh`>
octachron: ok, suppose I have type t = t2 foo, and in the module I have type t = t3 foo instead, and this is not rejected because t2 = t3
<dh`>
it is therefore also perfectly fine to have type t = t2 foo in the source module, and therefore there's no need to manually paste the definition from the interface
pi3ce has quit [Quit: No Ping reply in 180 seconds.]
<dh`>
as in, repeating it automatically is correct
pi3ce has joined #ocaml
<dh`>
null: maybe I'm getting mixed up but there are definitely cases where you don't have to paste in coq that you do in ocaml
<octachron>
Nope, because you might not know that `t2=t3` yet, and you need the definition right at this point.
<octachron>
(and a better example would `type t = A of int * int` versus `type u = A of t2` in the interface.
<octachron>
and t2 is abstract in the interface.
<octachron>
or `type t = A of (Make(B).t * int)` where neither `Make` nor `B` exists in the interface.
<dh`>
again, why would it be wrong to have "type t = A of t2" in the implementation? If t2 is defined in the interface it must be available in the implementation as well
<dh`>
I'm not proposing automatically pasting from the implementation to the interface, I'm claiming there's no need to repeat complete declarations from the interface in the implementation
<octachron>
Not at the point where you are typing t`.
<octachron>
And this claim is wrong.
<dh`>
so your argument is that it's possible to generate unresolvable ordering problems? I don't buy it
<dh`>
if there's a place in the implementation you can paste the definition of t by hand, you can also have the compiler paste it there
<dh`>
plus, if there are a few oddball cases where you still need to paste it by hand, what's the problem? none of this occurs in the common case
<discocaml>
<contextfreebeer> I'm not familiar with that
<discocaml>
<contextfreebeer> something like `type t := u`?
<octachron>
Ok, I agree that the copy-pastable is doable at least for linearly ordered type definitions (but it might cover a smaller subset that you think)
<octachron>
We could have a `[@@pinned]` attribute that pulls the definition from the mli, and check that it involves only external types and previously pinned type constructors.
<dh`>
octachron: ok, granted, this won't work: sig S = type t1;; type t2 = T2A * T2B of t1 end;; module M = struct type t1 = T1 of t2 and t2 = T2A * T2B of t1 end
<dh`>
because the definition is not actually complete in the .mli file but you can't tell that by looking at it
<discocaml>
<faldor20> I think that language features do have a significant impact, particularly in this case. For example, a description of what a function does, is more likely to go out of date over time, if it is located far away from the function's definition. Simply because while editing the function you aren't naturally forced to read its description.
<dh`>
faldor20: I've heard that claim many times, I've not found it to be actually true.
<dh`>
comments on _the same line_ go out of date
wingsorc has joined #ocaml
<discocaml>
<faldor20> Well I'm not saying it always prevents it, and I can only really speak to my own experience. Where mli files tend to be a bit neglected when I'm busy making actual changes.
<discocaml>
<faldor20>
<discocaml>
<faldor20> Another aspect is from a tooling perspective, while getting completions within a module functions have no documentation if that documentation is in an mli file. Or if the docs are in the ml file, the opposite problem exists.
<discocaml>
<faldor20> Well I'm not saying it always prevents it, and I can only really speak to my own experience. Where mli files tend to be a bit neglected when I'm busy making actual changes because they are out of sight.
<discocaml>
<faldor20>
<discocaml>
<faldor20> Another aspect is from a tooling perspective, while getting completions within a module functions have no documentation if that documentation is in an mli file. Or if the docs are in the ml file, the opposite problem exists.
<discocaml>
<limp.biskit> i don’t recall having that issue with va code
<dh`>
my experience is that if you want docs to be up to date, you have to foster a culture that values maintaining docs
<dh`>
and that trying to mix docs with source both doesn't help this and also makes for worse docs and worse source
<discocaml>
<limp.biskit> has anybody used custom runtime events yet?
<discocaml>
<limp.biskit> i’ve been looking at ways to add tracing into an existing code base for debugging and they look rather interesting
<dh`>
I agree that sometimes it's not clear which comments should go in the .ml file and which should go in the .mli file; however, people have been dealing with this for decades in .c/.h files and they get along
<discocaml>
<limp.biskit> tbf i’ve heard plenty of pain points with header files
<dh`>
there are various ways to misuse them that aren't permitted for .mli files
<dh`>
especially in the C++ world
<discocaml>
<limp.biskit> i think templates scared me off ever learning c++, and i actually like macros
<dh`>
templates are just misbegotten type parameters
<discocaml>
<limp.biskit> c++ is just misbegotten rust
<dh`>
c++ is much more misbegotten than that
Serpent7776 has quit [Ping timeout: 252 seconds]
bartholin has quit [Quit: Leaving]
jabuxas_ has quit [Quit: oops :p]
jabuxas has joined #ocaml
jabuxas has quit [Read error: Connection reset by peer]
jabuxas has joined #ocaml
jabuxas has quit [Read error: Connection reset by peer]
jabuxas has joined #ocaml
troydm has joined #ocaml
jabuxas has quit [Read error: Connection reset by peer]
jabuxas_ has joined #ocaml
jabuxas_ has quit [Read error: Connection reset by peer]
jabuxas has joined #ocaml
Tuplanolla has quit [Quit: Leaving.]
jabuxas has quit [Read error: Connection reset by peer]
jabuxas_ has joined #ocaml
jabuxas_ has quit [Remote host closed the connection]