How does Scala handle Java style package statements - java

This sounds embarrassing. My purpose is to understand how Scala treats package statements, written in the Java style. To this end, I wrote up a little example class (that I named DinnerTimeP.scala as below:
package dinnertime
class Dinner {
val veggie = "broccoli"
def announceDinner(veggie: String) {
println("Dinner happens to be tasteless " + veggie + " soup")
}
}
I have a folder called scaladev, under which I have created the package folder, dinnertime. Under this package lives DinnerTimeP.scala. On the DOS command I then navigate to dinnertime and compile the file DinnerTimeP (the name sounds silly) with scalac as below.
C:\scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime>set CLASSPATH=.;C:\scala- 2.9.1.final\scala-2.9.1.final\scaladev
C:\scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime>scalac DinnerTimeP.scala
I was hoping to find Dinner.class generated right under the dinnertime folder and sitting next to the source file DinnerTimeP.scala.
To confirm my understanding, I created a HelloWorld.java program under the same folder:
package dinnertime;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
I compiled HelloWorld.java on the command line as follows:
C:\scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime>javac HelloWorld.java
The HelloWorld.class file was generated right next to its source file.
This was the exact situation I wanted to see with the Scala source file and its compiled file.
Instead I see a new package folder generated by Scala inside the package folder dinnertime.
This might be naive. I am probably betraying a fundamental understanding of Scala and packages, but I was perplexed by this behaviour.
This is the problem I can't explain to myself: Why is the nested package created for the newly generated class file. This is the problem to which I which I had hoped to solve, based on my own sincere efforts
Because my experience with Scala at the present time is limited, I have resorted to asking the Scala gurus on stackoverflow to help me understand what is going on and why?
Is there a reason for this nested package to be created by Scala and not by Java?

Tomasz explained everything you need to get it working, so let me explain the why.
Scala does not mandate that source files be in a directory hierarchy that reflects the packages. That is, Dinner.scala could be anywhere: it simply doesn't matter.
And, to be really clear, even if you have a complex package hierarchy, deep and with multiple subpackages at each level, you can put all source files in a single directory. The directory where Scala files are put in is not relevant.
Sorry for giving it so much emphasis, but coming from Java it might be difficult to grasp this.
Ok, now, how to explain dinnertime/Dinner.class? Well, JVM demands that class file be put in a directory hierarchy that corresponds to the package names, so even if Scala source files can be put in arbitrary directories, scalac must produce an output whose directory structure reflects the package names.
So, to review everything, Scala doesn't care what directory you were in, so it ignored the fact that you were in a directory called dinnertime. However, since the source code indicated that the class was in a package named dinnertime, it created such directory and put the class file in it. It assumed the base for that was the current directory, which can be changed with the -d parameter, as per Tomasz answer.

First of all try compiling from the root directory, so that dinnertime is a subdirectory:
$ javac dinnertime/HelloWorld.java
and:
$ scalac dinnertime/Dinner.scala
They both produce the same output, i.e. in both cases .class file is placed under dinnertime subdirectory.
The difference arises when you run a compiler inside a package. Turns out javac is clever enough to put target binary files relative to root directory, not current direcotyr. This is not the case with scalac which always uses current directory as base. You can easily fix this by using -d parameter:
$ cd dinnertime
$ scalac -d .. Dinner.scala

Related

About compiling Java through terminal javac

I am a Java newbie, just started learning it in college, and my class is using NetBeans but I'd like to use VSCode.
The professor told us that every Java file should start with:
package nameofthepackage
So that Java knows to which package the class (file) I created belongs to.
So I always create this structure:
I create a folder with the name of the main class, and inside this folder I make a src folder that will store the Java files. Eg:
MyJavaProject/src/MyJavaProject.java
I always name the main .Java file the same as the project folder name.
And when I compile I use javac with the -cp parameter to specify that the src folder is the classpath folder, where it should look for the .Java files I create.
I also always tell javac to compile all the files inside the src folder, using the * wildcard.
The issue is that with this line on top of my .Java files, javac compiles all the files, but I can't execute the bytecode because it complains it can't find the classes I created, even the main one.
As Soon as I remove the package line from the top of the files, I can compile and run the code.
So far it's good, but for any more complex projects this is gonna be really annoying.
Any ideas how can I fix this?
You need to specify the full name (with package) of the class that contains the main function.
Assuming the class MyJavaProject is the one containing your main, that would be:
java nameofthepackage.MyJavaProject
This is assuming you built it with
javac -d . MyJavaProject.java
It would create your target class in a directory structure like:
nameofthepackage\MyJavaProject.class

How does Javac work for multiple files, directories, classes and source?

I'm trying to figure out how javac works with regard to stuff like sourcepath, classpath and prebuilt classes etc. I'm trying to read the documentation, but can't really make sense of it.
I've tried to think of some sample cases below.
If I'm compiling a single file onlyfile.java which has no dependencies, which has 2 classes A and B , and class A uses class B , does class B need to be defined/declared before A ? Or is javac smart and does multiple passes or something like that ?
root.java uses another class in a file file2.java located in the same folder. If I execute javac root.java , how does javac know to search the folder for the class file and if not found , for source file instead ?
How does the above work if the file2 is located in a subdirectory ?
EDIT:
I read somewhere that import is just a way to cut down on typing rather than "loading" anything like in python.
Suppose that I'm building only 1 java file which uses multiple other classes, and that these class files already exist. Without import, the a.b.c.d part of the class object already tells me where to search for the class file, then why a cp option ?
1) If you compile class A which uses class B then class B will be compelled as well. If you compile class B (which is used inside A, but A is not used inside B), class A will not be compelled. Find more details end examples here.
2) javac searches inside source-path and class-path. If you run javac without arguments like javac A.java it sets classpath and sourcepath to current directory. If requested class is not found neither in classpath nor in sourcepath you'll have compilation error.
3) Java has strict rules for project structure. You can't simply place source file to another folder without updating file content.
Every folder in the project should have folder hierarchy with respect of package declaration.
Definition: A package is a grouping of related types providing access protection and name space management.
for instance if you have class A.java with package declaration like this
package com.mycompany;
The corresponding folder structure should look like this:
com/mycompany/A.java
If you follow this rules compiler will be able to resolve dependencies just like I explained in #1. Find more information here.
For first two options try with javac *.java
Duplicate of Compiling Multiple Classes (Console) in Java

When should I set class path?

public class a {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
For the above code, I can run it by javac a.java, and then java a.
But if I add a package for it:
package hello;
public class a {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
I need add the classpath -cp in order to run it: java -cp ../ hello.a
Why I do not need to set the classpath in the first situation? When do I need to add -cp?
To answer your question
When should I set my classpath
Always, as you work on more complex projects you will find that your classpath will almost always need to be set. This will either be done manually like you have done with -cp command or by your IDE.
To answer your second question
Why I do not need to set the classpath in the first situation
I first need to explain a little bit about classpaths. In short classpath exist to tell the VM where to look for your files. In the first situation since you didnt have a package the default location was used to find your class so no classpath was needed. However when you complicated things and added a package at this point a classpath is needed
The classpath is where java (the program) looks for classes. The default contains a bunch of system-wide things (for the JDK), and then also the current directory: ..
Without the package line, your class was in the "default package," which is basically no package. This means its full name is a (more or less), and java will look for it in a file called $CP_ELEM/a.class for each element CP_ELEM in the classpath. In the default case, that amounts to ./a.class, which is fine because that file exists.
With the package line, your class is in the hello package, and its full name is hello.a. That means that java will look for it in $CP_ELEM/hello/a.class, which amounts to ./hello/a.class -- which doesn't exist. But if the directory you're in happens to be called "hello", then java -cp .. hello.a, which amounts to looking in ../hello/a.class, will work.
Classpath is like telling the system where to find my classes:
If you don't have a classpath the java will try to load the class
from the default directory (Probably where you're running the command at).
Now let's say you put your compiled classes in folder "bin" and sources in "src" folder
To tell the system to load the classes from "bin" folder you have to give him the following parameter:
-cp bin;
Also i see you don't understand the packaging system in java so here's fast explain:
Packaging is like you the directory of your class for example:
If you set the class's package to package a; and your classpath directory is set to "bin"
You have to create folder called "a" in "bin" folder, and then move the compiled class there, do the same for the source file, but in "src" folder
Just saying you could use eclipse which is located at : http://www.eclipse.org
If this didn't help you, Then take a look at this: https://www3.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html

Java packages and compilation (why, not how)

I'm working on some Java code in eclipse. Code is contained in a single class called Adder, which in Eclipse is in the package org.processing. The first thing in the class file is the line
package org.processing
Q1) What, exactly is this line doing? Why is there, what's it's role.
The code runs fine in eclipse, however, when I move into the workspace if I go to the src/org/processing/ folder in src, compile with javac Adder.class when I try and run using java Adder I get the following error
java.lang.NoClassDefFoundError: Adder (wrong name: org/processing/Adder)
On the other hand, if I compile from src using
javac org/processing/Adder.java
and I can run it from src using java org.processing.Adder but STILL not from within the processing directory.
Q2) Does this mean that compilation is always relative to directory structure?
Finally, if I remove the package org.processing line from the start are the .class file I can compile and run from within the .class file's directory.
Q3) Why is all this the way it is? I can fully understand enforcing a directory structure for code development, but once you're in bytecode this seems a bit over the top, because now I can (apparently) only run the bytecode from one director (src) using java org.processing.Adder. Now, I'm sure I'm missing the point here, so if someone could point out what it is, that would be great.
The compiler has to be able to find related source code files when compiling. This is why the package and directory structure must agree for source code. Similarly, the JVM must be able to find referenced .class files. So the same directory structure is required at runtime. It's no more complex than that.
Q1) The issue here is that once you got into the folders that represent your package hierarchy, you set that as the working directory. It's gonna look inside of org/processing/Adder for the path org/processing/Adder (essentially looking from the root for org/processing/Adder/org/processing/Adder). You need to call it from the root with the full path. The purpose of packages is A: to organize related classes into groups. And B: Along with A, classes in package Foo.bar can't view private classes in other packages, as they are like internal classes for that package, only the package they're in can use them
Q2) Yes
Q3) The paths are used as a basic structure for the JVM to know where exactly the class files (each containing their bytecode) are. If you change where you call it from, your basically trying to change the location for the JVM to look for the class files, but their true location hasn't changed.
The short answer - Packages help keep your project structure well-organized, allow you to reuse names (try having two classes named Account), and are a general convention for very large projects. They're nothing more than folder structures, but why they're used can burn beginners pretty badly. Funnily enough, with a project less than 5 classes, you probably won't need it.
What, exactly is this line doing? Why is there, what's it's role.
The line
package org.processing
is telling Java that this class file lives in a folder called /org/processing. This allows you to have a class which is fully defined as org.processing.Processor here, and in another folder - let's say /org/account/processing, you can have a class that's fully defined as org.account.processing.Processor. Yes, both use the same name, but they won't collide - they're in different packages. If you do decide to use them in the same class, you would have to be explicit about which one you want to use, either through the use of either import statements or the fully qualified object name.
Does this mean that compilation is always relative to directory structure?
Yes. Java and most other languages have a concept known as a classpath. Anything on this classpath can be compiled and run, and by default, the current directory you're in is on the classpath for compilation and execution. To place other files on the classpath, you would have to use another command-line invocation to your compilation:
javac -sourcepath /path/to/source MainClass.java
...and this would compile everything in your source path to your current directory, neatly organized in the folder structure specified by your package statements.
To run them, as you've already established, you would need to include the compiled source in your classpath, and then execute via the fully qualified object name:
java -cp /path/to/source org.main.MainClass
Why is all this the way it is?
Like I said before, this is mostly useful for very large projects, or projects that involve a lot of other classes and demand structure/organization, such as Android. It does a few things:
It keeps source organized in an easy-to-locate structure. You don't have objects scattered all over the place.
It keeps the scope of your objects clear. If I had a package named org.music.db, then it's pretty clear that I'm messing with objects that deal with the database and persistence. If I had a package named org.music.gui, then it's clear that this package deals with the presentation side. This can help when you want to create a new feature, or update/refactor an existing one; you can remember what it does, but you can't recall its name exactly.
It allows you to have objects with the same name. There is more than one type of Map out there, and if you're using projects that pull that in, you'd want to be able to specify which Map you get - again, accomplished through either imports or the fully qualified object name.
For Q1: The package declaration allows you to guarantee that your class will never be mistaken for another class with the same name. This is why most programmers put their company's name in the package; it's unlikely that there will be a conflict.
For Q2: There is a one-to-one correspondence between the package structure and the directory structure. The short of it is that directories and packages must be the same, excepting the package is usually rooted under a folder called src.
For Q3: Once it's compiled, the class files will probably be in the appropriate folders in a jar file. Your ant or maven tasks will build the jar file so you won't really have to bother with it beyond getting the ant task set up the first time.

Package name is different than the folder structure but still Java code compiles

I am using Notepad++ to write my Java code and Command Prompt to compile and run it.
Following is my sample Java code,
package abraKadabra;
public class SuperClass{
protected int anInstance;
public static void main(String [] abc){
System.out.println("Hello");
}
}
However, this file is in the following folder structure :
"usingprotected\superPkg" (usingProtected is a folder somewhere in the hierarchy in C:)
So, my package name here should be something like usingProtected.superPkg instead of abraKadabra as I wrote it.
But, when I compile this Java code from command prompt, it compiles fine with no error or warnings. Why is it so? Shouldn't the package name adhere to the folder structure?
And if it should, how would it adhere?
For e.g. if my package name is usingProtected.superPkg, will the compiler check in the reverse order. The present working directory should be superPkg, then the parent directory should be usingProtected and its done. Is it how it checks the folder structure with package name?
The Java language specification doesn't force files to be in a certain directory. It optionally allows the compiler to require that public classes are in files with the same name of the class, but I don't think there's anything similar for packages. Section 7.2.1 talks about possible storage options in a file system, but it doesn't say anything about enforcing source code structure, as far as I can see.
However, it's best practice - and a pretty much universally accepted convention - to reflect the package structure in the source directory structure... and javac will use this to try to find source files which aren't explicitly specified to be compiled.
Note that if you're compiling from the command line, by default each class will appear in the same location as the corresponding source file, but if you use the "-d" option (e.g. "-d bin") the compiler will build an appropriate output directory structure for you, rooted in the specified directory.
After experimenting a bit, I got the way how to use package name and run Java class files from command prompt.
Suppose following is my Java source file:-
package mySample;
public abstract class Sample{
public static void main(String... a){
System.out.println("Hello ambiguity");
}
}
This file is in directory "D:\Code N Code\CommandLine".
Now, when compile the source code (by going to the above directory from cmd) using following command:-
javac -d . Sample.java
This automatically creates "mySample" folder in my current directory. So, my class file Sample.class is present in directory "D:\Code N Code\CommandLine\mySample". Compiler created this new folder "mySample" from the package name that I gave in my source code.
So if I had given my package name to be "package com.mySample", compiler would create two directories and place my class file in "D:\Code N Code\CommandLine\com\mySample".
Now, I am still in the present working directory i.e. in "D:\Code N Code\CommandLine". And to run my class file, I give the following command:
java mySample.Sample
So, I give the complete hierarchy of package and then the class name. The Java Interpreter will search the current directory for "mySample" directory and in that for "Sample.class". It gets it right and runs it successfully. :)
Now, when I asked that why it compiles my wrong package source code, it would compile the code successfully though, but it gives NoClassDefFoundError when I run my class file. So above method can be used to use package names from command line.
If you're compiling a single class, javac doesn't need to look elsewhere for it. It'll just compile the file as is and put the resulting .class into the same folder. However, you generally won't be able to use the class til you put it into an "abraKadabra" directory in one of the directories in the class path.
If your class uses another class in the package, though, you might have problems compiling it where it is, for the same reason (javac wants to find the class and make sure it has the methods and such that your class uses).
Java compiler does not check the directory structure when it compiles source files. As you mentioned, suppose you have a source file that starts with the directive
package abraKadabra;
You can compile the file even if it is not contained in a subdirectory .../abraKadabra . The source file will compile without errors if it doesn’t depend on other packages. However, the resulting program will not run (unless also including package name in execution). The virtual machine won’t find the resulting classes when you try to run the program.

Categories