Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 11:30
    marksmithson opened #2243
  • 10:45
    Sporarum edited #9792
  • 08:57
    yikf commented #12504
  • 08:52
    lrytz closed #12504
  • 08:52
    lrytz commented #12504
  • 08:51
    yikf edited #12504
  • 08:46
    yikf opened #12504
  • 07:41

    lrytz on 2.13.x

    fix build (JDK 17 + bootstrappe… Merge pull request #9816 from S… (compare)

  • 07:41
    lrytz closed #9816
  • 04:35
    SethTisue synchronize #1512
  • 02:10
    SethTisue edited #1511
  • 02:10
    SethTisue edited #1512
  • 02:09
    SethTisue labeled #1512
  • 02:09
    SethTisue labeled #1511
  • 02:09
    SethTisue assigned #1512
  • 02:09
    SethTisue opened #1512
  • 02:08
    SethTisue opened #1511
  • 00:23
    SethTisue commented #9815
  • 00:23
    SethTisue review_requested #9816
  • 00:22
    SethTisue edited #9816
Guillaume Martres
@smarter
Bjorn Regnell
@bjornregnell
You need to put the worksheet in src/ceremony and yes console in sbt is nice; and also Compile / console / initialCommands
we use it but later
the first week i want one file, top-level defs and just rock :)
Guillaume Martres
@smarter
ah, I don't know how metals handles source directories, if it respects the sbt config you should be able to put worksheet files in the root directory and they'll be part of the root project
Bjorn Regnell
@bjornregnell
all tweaks can be done, but one click rules :)
Guillaume Martres
@smarter
sbt default list of source directories contains "." and "./src/main/scala/" iirc
Bjorn Regnell
@bjornregnell
yes but metals is confused about default package - let me see if I can find the issue
Guillaume Martres
@smarter
ok I have no idea what metals is doing here
Bjorn Regnell
@bjornregnell
BTW: I want them, when we have gotten some weeks into the course, to at least once to set up the -classpath themselves with at least one jar and at least once compile more than one file in terminal to understand a bit of what is happen under the hood (what is a package and a code unit etc and what files are involved). => So I want scalac on their path.
How "old" are your students? What courses have they taken before?
Guillaume Martres
@smarter
they're second year CS students
they see Java in their first year although that's changing to python now apparently
Bjorn Regnell
@bjornregnell
so they have already some tacit knowledge internalized, diffusing from the university walls around them :)
that old pyhton is taking the planet with storm
do you know how many that start CS year 1 with no coding experience at all?
Guillaume Martres
@smarter
no, but most I'd say
Bjorn Regnell
@bjornregnell
yeah, I guess your pre-knowledge span is perhaps less than mine, and the minimum level is obviously higher for year 2
One reason that I put emphasis on at least once do stuff in terminal without IDE stuff is that before I took over the then Java course with all Eclipse, teachers in later curses complained that students did not know how to do "simple" stuff in terminal... Nowadays their terminal street-smartness has improved significantly :)
Override-6
@Override-6
Hey, i am currently trying to generate scala sources code in order to generate classes at runtime. The concept of this project is to generate a class that will extend a given class then override every methods of the super classes (This will allow me to make a RMI system). In order to generate valid method overriding, i have to reproduce the exact same signature. I have a problem concerning the typing (type parameters, return type, argument types), and more precisely when the type declaration is this.type. With the wonderful reflection library, i can get a type from a point of view (let's say i have a class A[T] and an implementation B extends A[String], i can get the type of T from the point of view of the B class which is String (with Type#asSeenFrom)). So, for my tests, i want to generate a class extending from a pretty complex class (PuppetListBuffer[A] extends ListBuffer[A]). This type contains a method (def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, this.type]) declared in Iterable.scala. As you can see, the return type of this method contains a this.type type declaration. The problem is that since i use Type#asSeenFrom in order to get a type seen from the ListBuffer class, the result that i get is LazyZip2[A, B, ListBuffer[A]], which is quite satisfying but it's not the valid type declaration for a method overriding signature (must be this.type instead of ListBuffer[A]), and that's why scalac refuses to compile my class every time.
So, do you know if it's possible to get the Point of view of an implementation ?
or, do you have any other way to support this ?
zygfryd
@zygfryd
How are you going to deal with final classes and final methods? What exactly is the overriding code doing?
Rob Norris
@tpolecat
If you limit yourself to interfaces (as Java RMI does) you can use the dynamic proxy stuff in the JDK and you don't have to mess with macros or code generation.
Seth Tisue
@SethTisue
@Override-6 trying to reverse engineer source code from the information available via reflection sounds like a really difficult problem to me
Override-6
@Override-6
@zygfryd just add some filter to methods you have to generate :p
Override-6
@Override-6
I would like to make a more complex and autonomous rmi system, so limiting to interfaces is great but not enough (With the system i'm trying to make, i could be able to synchronise instances of any object i want (Map, List, Player, World etc...) and this is more easy to use than to create interfaces for this behavior
@SethTisue but scala does it ? in any case, it is able to find this kind of information from compiled classes. i only have difficulties with typings, is it possible to make scalac regardless on typing ?
Override-6
@Override-6
scala compiler*
Override-6
@Override-6

What exactly is the overriding code doing?

Here is the method who is in charge of generating the right return type declaration:

private def getReturnType(method: MethodDescription): String = {
            val symbol  = method.symbol
            val tParams = method.desc.classType.typeParams
            val tpe     = symbol.returnType
            renderTypes(Seq(( {
                val base        = method.desc.classType
                val methodOwner = symbol.owner
                tpe.asSeenFrom(base, methodOwner).finalResultType //here is where i set the Point Of View of the type from the ListBuffer class
            }, tParams.indexOf(tpe))), symbol, tParams)
                    .mkString("")
        }

here is the generated method that i talked about:

    override def lazyZip[B](arg1: scala.collection.Iterable[B]): scala.collection.LazyZip2[A, B, scala.collection.mutable.ListBuffer[A]] = { //here it is ListBuffer[A] instead of this.type
        if (choreographer.isMethodExecutionForcedToLocal || !description.isRMIEnabled(-40452569)) {
            return super.lazyZip[B](arg1)
        }
        val args = Array[Any](Array[Any](arg1))
        if (description.isInvokeOnly(-40452569)) {
            puppeteer.sendInvoke(-40452569, args)
            var localResult: scala.collection.LazyZip2[A, B, scala.collection.mutable.ListBuffer[A]] = JavaUtils.getNull
            if (description.isLocalInvocationForced(-40452569)) {
                localResult = super.lazyZip[B](arg1)
            }
            return JavaUtils.getNull
        }
        var result: scala.collection.LazyZip2[A, B, scala.collection.mutable.ListBuffer[A]] = JavaUtils.getNull
        if (description.isLocalInvocationForced(-40452569)) {
            result = super.lazyZip[B](arg1)
            puppeteer.sendInvoke(-40452569, args)
        } else {
            result = puppeteer.sendInvokeAndWaitResult(-40452569, args)
        }
        result
    }

(you can take a cleaner look at the blueprint if you want: )

    override def $MethodName$$GenericTypesIn$$ParamsIn$: $ReturnType$ = {
        if (choreographer.isMethodExecutionForcedToLocal || !description.isRMIEnabled($MethodID$)) {
            return super.$MethodName$$GenericTypesOut$$ParamsOut$
        }
        val args = Array[Any]($ParamsOutArray$)
        if (description.isInvokeOnly($MethodID$)) {
            puppeteer.sendInvoke($MethodID$, args)
            var localResult: $ReturnType$ = $DefaultReturnType$
            if (description.isLocalInvocationForced($MethodID$)) {
                localResult = super.$MethodName$$GenericTypesOut$$ParamsOut$
            }
            return $InvokeOnlyResult$
        }
        var result: $ReturnType$ = $DefaultReturnType$
        if (description.isLocalInvocationForced($MethodID$)) {
            result = super.$MethodName$$GenericTypesOut$$ParamsOut$
            puppeteer.sendInvoke($MethodID$, args)
        } else {
            result = puppeteer.sendInvokeAndWaitResult($MethodID$, args)
        }
        result
    }
and here one of the scalac's error messages:
found : scala.collection.LazyZip2[A,B,PuppetListBuffer.this.type] required: scala.collection.LazyZip2[A,B,scala.collection.mutable.ListBuffer[A]] Note: PuppetListBuffer.this.type <: scala.collection.mutable.ListBuffer[A], but class LazyZip2 is invariant in type C1. You may wish to investigate a wildcard type such as_ <: scala.collection.mutable.ListBuffer[A]. (SLS 3.2.10) return super.lazyZip[B](arg1)
it requires this.type but got ListBuffer[A]
Princess | April
@NthPortal

but scala does it

the scala signatures of methods are contained in classfile annotations, and that's what the scala compiler reads; it does not get you source code back

Override-6
@Override-6
i dont want the source code back
i just want to retrieve the signature, like scalac
zygfryd
@zygfryd
This doesn't seem like a great idea to me, because doing synchronous request-response networking at that granularity is bound to suck; but if I had to do it, I wouldn't be generating Scala at all, because the compiler is a massive, slow dependency, that's very hard to satisfy (in this instance for little reason) - I'd just generate bytecode - where you can ignore the fine structure of the types involved
Override-6
@Override-6
I have created a system that allows to create blueprints for class generation, the fact that i use this system to generate the classes i want allows the user to customize his generation for rmi classes.
i make synchronous and asynchronous requests, the user choose between sync/async depending on the description field but that is a runtime thing
i tried to generate java sources, which is way more easy for java classes indeed, but java can't support some scala method signatures as they are too much complex for javac, so it is not a good solution i think
Override-6
@Override-6
Indeed i could generate Jbytecode, but is it hard to handle ? it scares me haha
if i generate bytecode i'll have to handle class extention, variable and methods which seems pretty hard
zygfryd
@zygfryd
With a library like BCEL only method bodies are hard I'd say; so it's best to put as much code as possible outside the generated part
Override-6
@Override-6
mhh okay, i think i'll generating bytecode once i'm sure that i can't retrieve the right types declarations
zygfryd
@zygfryd
Is def sequence0[T <: Tuple](tuple: Tuple.Map[T, IO]): IO[T] and then IO.sequence0((IO("foo"), IO(42))) supposed to infer one day, or does it not work by design? (IO.sequence0[(String, Int)]((IO("foo"), IO(42))) works, so I'm assuming the former)
Seth Tisue
@SethTisue

is it possible to make scalac regardless on typing ?

no... well, I mean, you can probably make just about anything compile if you use asInstanceOf and/or Any enough

i just want to retrieve the signature, like scalac

reflection already does that, you are already doing that. your original question was how to generate source code from that information, and that's what I said was going to be very hard

and yes, I mean even just generating source code of the signature is going to be hard. I understand that you don't need to convert method bodies to source code
Override-6
@Override-6
okay
Seth Tisue
@SethTisue
that said....., have you looked at https://scalameta.org ? it actually does support source code generation. there's a lot of machinery behind it, machinery you're unlikely to be able to match with hand-rolled code