Threads for pshirshov

  1. 3

    The worst part of gRPC is its crappy protobuf notation. This tool doesn’t address anything about that.

    I’m wondering why I got banned when I tried to promote another RPC tool with a throwaway account.

    1. 24

      I’m wondering why I got banned when I tried to promote another RPC tool with a throwaway account.

      Sockpuppeting on Lobsters is heavily frowned upon.

      1. 13

        promote … with a throwaway account.

        That. Don’t use throwaway accounts and shill projects.

        1. 4

          Do you mean the service definitions being .proto files? If so, DRPC has a very modular design, and all of the functionality is implemented by referring to only the interfaces defined in the main module. Because of that, you can effectively manually write out the code generated glue, or generate it in some other way. Here’s an example of that: https://play.golang.org/p/JQcS2A9S8QX

          1. 1

            I’m wondering why I got banned when I tried to promote another RPC tool with a throwaway account.

            Which tool were you trying to promote?

            1. 6

              He got banned again so we may never know

              1. 13

                Who thinks it’s a good idea to tell everybody they’re a spammer?

                1. 2

                  Growth hackers.

              2. 4

                The moderation log answers your question, fwiw.

                1. 4

                  You can check the moderation log for timestamp 2021-04-17 12:40 -0500

                  1. 1

                    click through to their username, which includes a ban reason.

                1. 2

                  A function does not need to be parsed and statically analyzed to figure out what it does. The function itself will tell you: Just call it and see.

                  The function will speak to you in a language determined by the arguments you pass it.

                  I like this idea, but isn’t it limited to straight-line code? Or, maybe it depends on which primitives your programming language lets you customize.

                  Suppose you want to pretty-print this function:

                  def square(x):
                      return x*x
                  

                  You can do it in Python because you can customize __mul__. But you probably can’t do it in Javascript.

                  Or suppose you want to pretty-print this function:

                  def abs(x):
                      if x < 0:
                          return -x
                      else:
                          return x
                  

                  You can customize __lt__, __neg__, and even __bool__, but you can’t make the if take both branches.

                  1. 4

                    Yeah, what you can get this way are traces. Not pretty-prints.

                    1. 2

                      Or suppose you want to pretty-print this function:

                      The trick here is to avoid primitive control flow.

                      For example, if you expose a list that the user can iterate over with a for-loop, that for-loop won’t be visible to you.

                      But if you expose a “foreach” method to which the user passes a function - that works just fine.

                      Or as another example, instead of returning a boolean that indicates whether a function is successful, return a Result object (like in Rust) which has a .or_else or .map method used to extract the value. Then you can take both branches by both calling, and not calling, the function passed to the .or_else or whatever method.

                      Of course, this is not always the most natural way to do things, but it can get pretty far. And in functional languages, that kind of design is fairly normal.

                      1. 5

                        Python doesn’t want you to avoid primitive control flow. If you write something you’d need monads (and therefore higher-kinded types), people will tell you it’s not idiomatic Python.

                        Since there isn’t any do-notation, it’d also going to look super weird, even before we start composing effects with monad transformers.

                        1. 1

                          But you can do quite a lot without monads or do-notation, as the examples show.

                        2. 1

                          I’m failing to see the point of all this. I have this function (Lua, where ‘//’ is integer division):

                          function dayofweek(date)
                            local a = (14 - date.month) // 12
                            local y = date.year - a
                            local m = date.month + 12 * a - 2
                            local d = date.day
                                    + y
                                    + y // 4
                                    - y // 100
                                    + y // 400
                                    + 31 * m // 12
                            return (d % 7) + 1
                          end
                          

                          Straightforward code, so no issues with flow control. In Lua, you can override each of the operators, but that still fails to capture the assignments, and even the return statement.

                          1. 3

                            It depends on what you want out. You’ll lose the assignments, but you could capture an expression tree of the arithmetic that needs to be done and print that or code generate from it or whatever.

                            Suppose that date is some object with overloaded arithmetic and it all falls out. The final return is of an expression including d, which referenced date, so if you have enough overloads you’ll get what you wanted out.

                            Kind of off-topic, but I like how a system with open classes and where all operations are really functions lets you do this stuff easily. For a prosiac example, consider the Measurements.jl package for Julia. It defines a type that contains a number and the uncertainty associated with that number. Overloaded functions allows you to pass an object of this type into any numeric function you like and get out a new measurement that has the uncertainty correctly propagated, but you can go beyond numeric functions and overload methods in plotting libraries and elsewhere and inexpensively get error propagation working with libraries that never considered it.

                          2. 1

                            The trick here is to avoid primitive control flow.

                            In case you are advocating indirection through operating on data structures, self-introspectable code, etc, I believe you should name particular concepts, otherwise you are doing an evil job.

                            Also In case you mean that - probably your post should be titled “Write intepreters, not compilers”?..

                          3. 1

                            If could possibly be implemented by allowing overloading branching on the if condition. Probably better if if itself is an expression.

                            The real problems are state changes and loops. Maybe if you statically rewrote loops into recursive calls, and just avoided mutation?

                            1. 1

                              Loops can be avoided cleanly - see my sibling comment about using foreach instead of loops.

                              State changes are fine if you’re doing those through methods that are part of an interface (rather than, say, directly reassigning a mutable variable to a different value)

                          1. 8

                            To be quiet honest I didn’t get what the author tried to say. I’m not sure if the author understands what message he tries to deliver. And the blog post needs some additional clarification. It makes little sense even with the “example”.

                            1. 3

                              It makes more sense if you know a lot of Haskell, where this sort of thing is somewhat common. You basically define your functions as a sort of DSL that operates over a typeclass (which is Haskell’s term for an interface, essentially) and then you can do different things depending what type you pick.

                              But since most people don’t know Haskell, the post falls flat.

                              1. 2

                                It’s a very common idiom in Lisp. The way that I was told to write Lisp code was to write a clear description of the problem and then a compiler that transformed it into the solution. I’ve not written more than a token amount of Lisp code, but when I’ve read code in this style it’s been very clear and comprehensible. If someone is arguing against this, I’d expect it to come with a lot of justification, rather than just assertion.

                                1. 1

                                  The problem is that Python, the language used in the examples, is not Lisp. Most languages aren’t like Lisp or Haskell in this way either.

                                  1. 1

                                    Do you have any examples of code like this, for the sake of learning?

                                    1. 1

                                      Principles of Artificial Intelligence Programming uses this technique; here’s a grammar for a subset of English.

                                  2. 1

                                    It makes more sense if you know a lot of Haskell

                                    Well, I believe I’m doing advanced Scala. I’m kinda familiar with TF, pure FP and these sorts of things. But still.

                                    To convert a function into some other type (executable code, or a pretty-printed program, or something else), the easiest way is to call the function, passing certain arguments, such that the desired type is returned from the function.

                                    This makes little sense. Probably this guy is trying to say that something about memoization and purity?.. Well, I have a function, (a, b) => a+b, how can I “convert it into some other type” so I can interpret it on different platforms?

                                    A function does not need to be parsed and statically analyzed to figure out what it does. The function itself will tell you: Just call it and see.

                                    What?.. Is he trying to say that I may infer function AST by building a mapping table for particular inputs and outputs?..

                                    The function will speak to you

                                    What “will speak to you” stands for?

                                    in a language determined by the arguments you pass it.

                                    Is he trying to say that a function may interpret an indirect program expressed by a data structure? Why to use such an obscure language then? Why not to show some examples and not to say something about TF?

                                    The fewer global variables and types that a function refers to, the more the function can speak in the language we desire, rather than a hard-coded predetermined langauge.

                                    What do “less/more” mean in this context? What kind of a “global variable” the author is speaking about? What about “global types”? What are “local types”? How evil is an “global variable” of type IO[A, Nothing, B]?

                                    How “Write code, not compilers” related to the content of the post?

                                1. 2

                                  It makes zero sense to trade one semiformal RPC convention for another.

                                  Just use formal RPC tools.

                                  1. 1

                                    Since I know Chef I’d probably reach for that in your situation (or, the open source version, CINC)

                                    1. 1

                                      Well, I’ve tried Chef and have no idea how to debug it.

                                      ‘package’ task with 21-element array argument works, the same tasks with 22 element array fails with a useless stacktrace.

                                    1. 2

                                      Oh, a rare example of a typer explncitly representing its work as a graph. We are doing similar things in distage (DI for Scala) and another project.

                                      1. 1

                                        That article would be so nice for year 2001 or 2002.

                                        In our days we have really type safe options, e.g. uPickle or circe.

                                        I don’t understand why do you promote reflection in 2021.

                                        1. 1

                                          Could you elaborate about how the libraries that you mentioned help in providing dynamic data access in Java?

                                        1. 2

                                          Here is my talk about fakes/mocks, dual tests, associated issues and our solution: https://youtu.be/CzpvjkUukAs

                                          And here is more: https://blog.7mind.io/constructive-test-taxonomy.html

                                          1. 4

                                            I wonder how does the categorisation help thinking in the TDD process. It seems to me that such tags, although very precise when looking back at the tests that are already written, would be too much for me to remember and to think about upfront.

                                            1. 2

                                              There are manu possible classes but each axis is simple enough to remember. A team may need some time to get used to the idea but once it happens - it helps. So, technically when you write a test you always know that you shouldn’t break encapsulation, should try to concentrate on contracts and should avoid any integrations. When you need something apart of that - you may think a bit how to choose the class with minimal weight which would work for you. The same applies for refactorings - you always have some basic guidelines on how to make a test “better”.

                                              It’s very hard to explain people thinking in traditional terms why their whitebox-evil tests don’t return invested efforts.

                                            1. 5

                                              A more natural metric for “Isolation”: expression, method, class, file, package, library, application, container (or machine/OS/box), cluster (or intranet), internet. A sort of generalization of lexical scope, or global variables. You might also split it up by mutability; testing your application’s installer might need ‘read’ access all the way up to the internet for downloading dependencies, but require write access only up to the container.

                                              1. 4

                                                Thanks for the ideas, I’ve added them to the post.

                                              1. 1

                                                Actually it’s not a big deal to combine microservice approach with monolithic one. The missing concept is a “Role” - a software component which may be shipped independently but able to run in a process together with other components. OSGi would make a good example. Also you may check my slides here: https://github.com/7mind/slides/blob/master/02-roles/target/roles.pdf (Scala-specific)